Blame view

drivers/spi/spi-pl022.c 68.6 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
3
4
   * A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
   *
aeef9915b   Linus Walleij   spi/pl022: use mo...
5
   * Copyright (C) 2008-2012 ST-Ericsson AB
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
6
7
8
9
10
11
12
13
   * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
   *
   * Author: Linus Walleij <linus.walleij@stericsson.com>
   *
   * Initial version inspired by:
   *	linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
   * Initial adoption to PL022 by:
   *      Sachin Verma <sachin.verma@st.com>
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
14
   */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
15
16
17
18
19
20
21
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/device.h>
  #include <linux/ioport.h>
  #include <linux/errno.h>
  #include <linux/interrupt.h>
  #include <linux/spi/spi.h>
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
22
23
24
25
26
27
  #include <linux/delay.h>
  #include <linux/clk.h>
  #include <linux/err.h>
  #include <linux/amba/bus.h>
  #include <linux/amba/pl022.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
28
  #include <linux/slab.h>
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
29
30
31
  #include <linux/dmaengine.h>
  #include <linux/dma-mapping.h>
  #include <linux/scatterlist.h>
bcda6ff8d   Rabin Vincent   spi/pl022: suppor...
32
  #include <linux/pm_runtime.h>
f6f46de10   Roland Stigge   spi/pl022: Add ch...
33
  #include <linux/gpio.h>
6d3952a7d   Roland Stigge   spi/pl022: Add de...
34
  #include <linux/of_gpio.h>
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
35
  #include <linux/pinctrl/consumer.h>
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  
  /*
   * This macro is used to define some register default values.
   * reg is masked with mask, the OR:ed with an (again masked)
   * val shifted sb steps to the left.
   */
  #define SSP_WRITE_BITS(reg, val, mask, sb) \
   ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
  
  /*
   * This macro is also used to define some default values.
   * It will just shift val by sb steps to the left and mask
   * the result with mask.
   */
  #define GEN_MASK_BITS(val, mask, sb) \
   (((val)<<(sb)) & (mask))
  
  #define DRIVE_TX		0
  #define DO_NOT_DRIVE_TX		1
  
  #define DO_NOT_QUEUE_DMA	0
  #define QUEUE_DMA		1
  
  #define RX_TRANSFER		1
  #define TX_TRANSFER		2
  
  /*
   * Macros to access SSP Registers with their offsets
   */
  #define SSP_CR0(r)	(r + 0x000)
  #define SSP_CR1(r)	(r + 0x004)
  #define SSP_DR(r)	(r + 0x008)
  #define SSP_SR(r)	(r + 0x00C)
  #define SSP_CPSR(r)	(r + 0x010)
  #define SSP_IMSC(r)	(r + 0x014)
  #define SSP_RIS(r)	(r + 0x018)
  #define SSP_MIS(r)	(r + 0x01C)
  #define SSP_ICR(r)	(r + 0x020)
  #define SSP_DMACR(r)	(r + 0x024)
db4fa45ed   Anders Berg   spi: pl022: Add s...
75
  #define SSP_CSR(r)	(r + 0x030) /* vendor extension */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  #define SSP_ITCR(r)	(r + 0x080)
  #define SSP_ITIP(r)	(r + 0x084)
  #define SSP_ITOP(r)	(r + 0x088)
  #define SSP_TDR(r)	(r + 0x08C)
  
  #define SSP_PID0(r)	(r + 0xFE0)
  #define SSP_PID1(r)	(r + 0xFE4)
  #define SSP_PID2(r)	(r + 0xFE8)
  #define SSP_PID3(r)	(r + 0xFEC)
  
  #define SSP_CID0(r)	(r + 0xFF0)
  #define SSP_CID1(r)	(r + 0xFF4)
  #define SSP_CID2(r)	(r + 0xFF8)
  #define SSP_CID3(r)	(r + 0xFFC)
  
  /*
   * SSP Control Register 0  - SSP_CR0
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
94
95
  #define SSP_CR0_MASK_DSS	(0x0FUL << 0)
  #define SSP_CR0_MASK_FRF	(0x3UL << 4)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
96
97
98
  #define SSP_CR0_MASK_SPO	(0x1UL << 6)
  #define SSP_CR0_MASK_SPH	(0x1UL << 7)
  #define SSP_CR0_MASK_SCR	(0xFFUL << 8)
556f4aeb7   Linus Walleij   spi/pl022: fix up...
99
100
101
102
103
104
105
106
107
  
  /*
   * The ST version of this block moves som bits
   * in SSP_CR0 and extends it to 32 bits
   */
  #define SSP_CR0_MASK_DSS_ST	(0x1FUL << 0)
  #define SSP_CR0_MASK_HALFDUP_ST	(0x1UL << 5)
  #define SSP_CR0_MASK_CSS_ST	(0x1FUL << 16)
  #define SSP_CR0_MASK_FRF_ST	(0x3UL << 21)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
108
109
110
111
112
113
114
  /*
   * SSP Control Register 0  - SSP_CR1
   */
  #define SSP_CR1_MASK_LBM	(0x1UL << 0)
  #define SSP_CR1_MASK_SSE	(0x1UL << 1)
  #define SSP_CR1_MASK_MS		(0x1UL << 2)
  #define SSP_CR1_MASK_SOD	(0x1UL << 3)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
115
116
  
  /*
556f4aeb7   Linus Walleij   spi/pl022: fix up...
117
118
   * The ST version of this block adds some bits
   * in SSP_CR1
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
119
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
120
121
122
123
124
  #define SSP_CR1_MASK_RENDN_ST	(0x1UL << 4)
  #define SSP_CR1_MASK_TENDN_ST	(0x1UL << 5)
  #define SSP_CR1_MASK_MWAIT_ST	(0x1UL << 6)
  #define SSP_CR1_MASK_RXIFLSEL_ST (0x7UL << 7)
  #define SSP_CR1_MASK_TXIFLSEL_ST (0x7UL << 10)
781c7b129   Linus Walleij   spi/pl022: add su...
125
126
  /* This one is only in the PL023 variant */
  #define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
127
128
129
130
131
132
133
  
  /*
   * SSP Status Register - SSP_SR
   */
  #define SSP_SR_MASK_TFE		(0x1UL << 0) /* Transmit FIFO empty */
  #define SSP_SR_MASK_TNF		(0x1UL << 1) /* Transmit FIFO not full */
  #define SSP_SR_MASK_RNE		(0x1UL << 2) /* Receive FIFO not empty */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
134
  #define SSP_SR_MASK_RFF		(0x1UL << 3) /* Receive FIFO full */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
135
136
137
138
139
140
141
142
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
185
186
187
188
189
190
  #define SSP_SR_MASK_BSY		(0x1UL << 4) /* Busy Flag */
  
  /*
   * SSP Clock Prescale Register  - SSP_CPSR
   */
  #define SSP_CPSR_MASK_CPSDVSR	(0xFFUL << 0)
  
  /*
   * SSP Interrupt Mask Set/Clear Register - SSP_IMSC
   */
  #define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */
  #define SSP_IMSC_MASK_RTIM  (0x1UL << 1) /* Receive timeout Interrupt mask */
  #define SSP_IMSC_MASK_RXIM  (0x1UL << 2) /* Receive FIFO Interrupt mask */
  #define SSP_IMSC_MASK_TXIM  (0x1UL << 3) /* Transmit FIFO Interrupt mask */
  
  /*
   * SSP Raw Interrupt Status Register - SSP_RIS
   */
  /* Receive Overrun Raw Interrupt status */
  #define SSP_RIS_MASK_RORRIS		(0x1UL << 0)
  /* Receive Timeout Raw Interrupt status */
  #define SSP_RIS_MASK_RTRIS		(0x1UL << 1)
  /* Receive FIFO Raw Interrupt status */
  #define SSP_RIS_MASK_RXRIS		(0x1UL << 2)
  /* Transmit FIFO Raw Interrupt status */
  #define SSP_RIS_MASK_TXRIS		(0x1UL << 3)
  
  /*
   * SSP Masked Interrupt Status Register - SSP_MIS
   */
  /* Receive Overrun Masked Interrupt status */
  #define SSP_MIS_MASK_RORMIS		(0x1UL << 0)
  /* Receive Timeout Masked Interrupt status */
  #define SSP_MIS_MASK_RTMIS		(0x1UL << 1)
  /* Receive FIFO Masked Interrupt status */
  #define SSP_MIS_MASK_RXMIS		(0x1UL << 2)
  /* Transmit FIFO Masked Interrupt status */
  #define SSP_MIS_MASK_TXMIS		(0x1UL << 3)
  
  /*
   * SSP Interrupt Clear Register - SSP_ICR
   */
  /* Receive Overrun Raw Clear Interrupt bit */
  #define SSP_ICR_MASK_RORIC		(0x1UL << 0)
  /* Receive Timeout Clear Interrupt bit */
  #define SSP_ICR_MASK_RTIC		(0x1UL << 1)
  
  /*
   * SSP DMA Control Register - SSP_DMACR
   */
  /* Receive DMA Enable bit */
  #define SSP_DMACR_MASK_RXDMAE		(0x1UL << 0)
  /* Transmit DMA Enable bit */
  #define SSP_DMACR_MASK_TXDMAE		(0x1UL << 1)
  
  /*
db4fa45ed   Anders Berg   spi: pl022: Add s...
191
192
193
194
195
196
   * SSP Chip Select Control Register - SSP_CSR
   * (vendor extension)
   */
  #define SSP_CSR_CSVALUE_MASK		(0x1FUL << 0)
  
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
   * SSP Integration Test control Register - SSP_ITCR
   */
  #define SSP_ITCR_MASK_ITEN		(0x1UL << 0)
  #define SSP_ITCR_MASK_TESTFIFO		(0x1UL << 1)
  
  /*
   * SSP Integration Test Input Register - SSP_ITIP
   */
  #define ITIP_MASK_SSPRXD		 (0x1UL << 0)
  #define ITIP_MASK_SSPFSSIN		 (0x1UL << 1)
  #define ITIP_MASK_SSPCLKIN		 (0x1UL << 2)
  #define ITIP_MASK_RXDMAC		 (0x1UL << 3)
  #define ITIP_MASK_TXDMAC		 (0x1UL << 4)
  #define ITIP_MASK_SSPTXDIN		 (0x1UL << 5)
  
  /*
   * SSP Integration Test output Register - SSP_ITOP
   */
  #define ITOP_MASK_SSPTXD		 (0x1UL << 0)
  #define ITOP_MASK_SSPFSSOUT		 (0x1UL << 1)
  #define ITOP_MASK_SSPCLKOUT		 (0x1UL << 2)
  #define ITOP_MASK_SSPOEn		 (0x1UL << 3)
  #define ITOP_MASK_SSPCTLOEn		 (0x1UL << 4)
  #define ITOP_MASK_RORINTR		 (0x1UL << 5)
  #define ITOP_MASK_RTINTR		 (0x1UL << 6)
  #define ITOP_MASK_RXINTR		 (0x1UL << 7)
  #define ITOP_MASK_TXINTR		 (0x1UL << 8)
  #define ITOP_MASK_INTR			 (0x1UL << 9)
  #define ITOP_MASK_RXDMABREQ		 (0x1UL << 10)
  #define ITOP_MASK_RXDMASREQ		 (0x1UL << 11)
  #define ITOP_MASK_TXDMABREQ		 (0x1UL << 12)
  #define ITOP_MASK_TXDMASREQ		 (0x1UL << 13)
  
  /*
   * SSP Test Data Register - SSP_TDR
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
233
  #define TDR_MASK_TESTDATA		(0xFFFFFFFF)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
234
235
236
237
238
239
240
  
  /*
   * Message State
   * we use the spi_message.state (void *) pointer to
   * hold a single state value, that's why all this
   * (void *) casting is done here.
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
241
242
243
244
  #define STATE_START			((void *) 0)
  #define STATE_RUNNING			((void *) 1)
  #define STATE_DONE			((void *) 2)
  #define STATE_ERROR			((void *) -1)
7aef2b646   Jiwei Sun   spi: pl022: add a...
245
  #define STATE_TIMEOUT			((void *) -2)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
246
247
  
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
248
249
   * SSP State - Whether Enabled or Disabled
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
250
251
  #define SSP_DISABLED			(0)
  #define SSP_ENABLED			(1)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
252
253
254
255
  
  /*
   * SSP DMA State - Whether DMA Enabled or Disabled
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
256
257
  #define SSP_DMA_DISABLED		(0)
  #define SSP_DMA_ENABLED			(1)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
258
259
260
261
  
  /*
   * SSP Clock Defaults
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
262
263
  #define SSP_DEFAULT_CLKRATE 0x2
  #define SSP_DEFAULT_PRESCALE 0x40
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  
  /*
   * SSP Clock Parameter ranges
   */
  #define CPSDVR_MIN 0x02
  #define CPSDVR_MAX 0xFE
  #define SCR_MIN 0x00
  #define SCR_MAX 0xFF
  
  /*
   * SSP Interrupt related Macros
   */
  #define DEFAULT_SSP_REG_IMSC  0x0UL
  #define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
85fa4e1f0   Alexander Sverdlin   spi: pl022: Don't...
278
279
280
281
282
283
  #define ENABLE_ALL_INTERRUPTS ( \
  	SSP_IMSC_MASK_RORIM | \
  	SSP_IMSC_MASK_RTIM | \
  	SSP_IMSC_MASK_RXIM | \
  	SSP_IMSC_MASK_TXIM \
  )
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
284
285
  
  #define CLEAR_ALL_INTERRUPTS  0x3
a18c266f8   Magnus Templing   spi/pl022: timeou...
286
  #define SPI_POLLING_TIMEOUT 1000
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
287
288
289
290
291
292
293
294
295
  /*
   * The type of reading going on on this chip
   */
  enum ssp_reading {
  	READING_NULL,
  	READING_U8,
  	READING_U16,
  	READING_U32
  };
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
296
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
   * The type of writing going on on this chip
   */
  enum ssp_writing {
  	WRITING_NULL,
  	WRITING_U8,
  	WRITING_U16,
  	WRITING_U32
  };
  
  /**
   * struct vendor_data - vendor-specific config parameters
   * for PL022 derivates
   * @fifodepth: depth of FIFOs (both)
   * @max_bpw: maximum number of bits per word
   * @unidir: supports unidirection transfers
556f4aeb7   Linus Walleij   spi/pl022: fix up...
312
313
   * @extended_cr: 32 bit wide control register 0 with extra
   * features and extra features in CR1 as found in the ST variants
781c7b129   Linus Walleij   spi/pl022: add su...
314
   * @pl023: supports a subset of the ST extensions called "PL023"
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
315
   * @loopback: supports loopback mode
db4fa45ed   Anders Berg   spi: pl022: Add s...
316
   * @internal_cs_ctrl: supports chip select control register
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
317
318
319
320
321
   */
  struct vendor_data {
  	int fifodepth;
  	int max_bpw;
  	bool unidir;
556f4aeb7   Linus Walleij   spi/pl022: fix up...
322
  	bool extended_cr;
781c7b129   Linus Walleij   spi/pl022: add su...
323
  	bool pl023;
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
324
  	bool loopback;
db4fa45ed   Anders Berg   spi: pl022: Add s...
325
  	bool internal_cs_ctrl;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
326
327
328
329
330
  };
  
  /**
   * struct pl022 - This is the private SSP driver data structure
   * @adev: AMBA device model hookup
12e8b325f   Linus Walleij   spi/pl022: minor ...
331
332
333
334
   * @vendor: vendor data for the IP block
   * @phybase: the physical memory where the SSP device resides
   * @virtbase: the virtual memory where the SSP is mapped
   * @clk: outgoing clock "SPICLK" for the SPI bus
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
335
336
   * @master: SPI framework hookup
   * @master_info: controller-specific data from machine setup
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
337
338
339
340
   * @pump_transfers: Tasklet used in Interrupt Transfer mode
   * @cur_msg: Pointer to current spi_message being processed
   * @cur_transfer: Pointer to current spi_transfer
   * @cur_chip: pointer to current clients chip(assigned from controller_state)
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
341
342
343
344
   * @next_msg_cs_active: the next message in the queue has been examined
   *  and it was found that it uses the same chip select as the previous
   *  message, so we left it active after the previous transfer, and it's
   *  active already.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
345
346
347
348
   * @tx: current position in TX buffer to be read
   * @tx_end: end position in TX buffer to be read
   * @rx: current position in RX buffer to be written
   * @rx_end: end position in RX buffer to be written
12e8b325f   Linus Walleij   spi/pl022: minor ...
349
350
351
   * @read: the type of read currently going on
   * @write: the type of write currently going on
   * @exp_fifo_level: expected FIFO level
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
352
353
   * @rx_lev_trig: receive FIFO watermark level which triggers IRQ
   * @tx_lev_trig: transmit FIFO watermark level which triggers IRQ
12e8b325f   Linus Walleij   spi/pl022: minor ...
354
355
356
357
358
   * @dma_rx_channel: optional channel for RX DMA
   * @dma_tx_channel: optional channel for TX DMA
   * @sgt_rx: scattertable for the RX transfer
   * @sgt_tx: scattertable for the TX transfer
   * @dummypage: a dummy page used for driving data on the bus with DMA
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
359
   * @dma_running: indicates whether DMA is in operation
f6f46de10   Roland Stigge   spi/pl022: Add ch...
360
361
   * @cur_cs: current chip select (gpio)
   * @chipselects: list of chipselects (gpios)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
362
363
364
365
366
367
368
369
370
   */
  struct pl022 {
  	struct amba_device		*adev;
  	struct vendor_data		*vendor;
  	resource_size_t			phybase;
  	void __iomem			*virtbase;
  	struct clk			*clk;
  	struct spi_master		*master;
  	struct pl022_ssp_controller	*master_info;
ffbbdd213   Linus Walleij   spi: create a mes...
371
  	/* Message per-transfer pump */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
372
373
374
375
  	struct tasklet_struct		pump_transfers;
  	struct spi_message		*cur_msg;
  	struct spi_transfer		*cur_transfer;
  	struct chip_data		*cur_chip;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
376
  	bool				next_msg_cs_active;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
377
378
379
380
381
382
  	void				*tx;
  	void				*tx_end;
  	void				*rx;
  	void				*rx_end;
  	enum ssp_reading		read;
  	enum ssp_writing		write;
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
383
  	u32				exp_fifo_level;
083be3f05   Linus Walleij   spi/pl022: initia...
384
385
  	enum ssp_rx_level_trig		rx_lev_trig;
  	enum ssp_tx_level_trig		tx_lev_trig;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
386
387
388
389
390
391
392
  	/* DMA settings */
  #ifdef CONFIG_DMA_ENGINE
  	struct dma_chan			*dma_rx_channel;
  	struct dma_chan			*dma_tx_channel;
  	struct sg_table			sgt_rx;
  	struct sg_table			sgt_tx;
  	char				*dummypage;
ffbbdd213   Linus Walleij   spi: create a mes...
393
  	bool				dma_running;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
394
  #endif
f6f46de10   Roland Stigge   spi/pl022: Add ch...
395
396
  	int cur_cs;
  	int *chipselects;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
397
398
399
400
  };
  
  /**
   * struct chip_data - To maintain runtime state of SSP for each client chip
556f4aeb7   Linus Walleij   spi/pl022: fix up...
401
402
   * @cr0: Value of control register CR0 of SSP - on later ST variants this
   *       register is 32 bits wide rather than just 16
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
403
404
405
406
407
   * @cr1: Value of control register CR1 of SSP
   * @dmacr: Value of DMA control Register of SSP
   * @cpsr: Value of Clock prescale register
   * @n_bytes: how many bytes(power of 2) reqd for a given data width of client
   * @enable_dma: Whether to enable DMA or not
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
408
   * @read: function ptr to be used to read when doing xfer for this chip
12e8b325f   Linus Walleij   spi/pl022: minor ...
409
   * @write: function ptr to be used to write when doing xfer for this chip
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
410
411
412
413
414
415
416
   * @cs_control: chip select callback provided by chip
   * @xfer_type: polling/interrupt/DMA
   *
   * Runtime state of the SSP controller, maintained per chip,
   * This would be set according to the current message that would be served
   */
  struct chip_data {
556f4aeb7   Linus Walleij   spi/pl022: fix up...
417
  	u32 cr0;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
418
419
420
421
  	u16 cr1;
  	u16 dmacr;
  	u16 cpsr;
  	u8 n_bytes;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
422
  	bool enable_dma;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  	enum ssp_reading read;
  	enum ssp_writing write;
  	void (*cs_control) (u32 command);
  	int xfer_type;
  };
  
  /**
   * null_cs_control - Dummy chip select function
   * @command: select/delect the chip
   *
   * If no chip select function is provided by client this is used as dummy
   * chip select
   */
  static void null_cs_control(u32 command)
  {
  	pr_debug("pl022: dummy chip select control, CS=0x%x
  ", command);
  }
db4fa45ed   Anders Berg   spi: pl022: Add s...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  /**
   * internal_cs_control - Control chip select signals via SSP_CSR.
   * @pl022: SSP driver private data structure
   * @command: select/delect the chip
   *
   * Used on controller with internal chip select control via SSP_CSR register
   * (vendor extension). Each of the 5 LSB in the register controls one chip
   * select signal.
   */
  static void internal_cs_control(struct pl022 *pl022, u32 command)
  {
  	u32 tmp;
  
  	tmp = readw(SSP_CSR(pl022->virtbase));
  	if (command == SSP_CHIP_SELECT)
  		tmp &= ~BIT(pl022->cur_cs);
  	else
  		tmp |= BIT(pl022->cur_cs);
  	writew(tmp, SSP_CSR(pl022->virtbase));
  }
f6f46de10   Roland Stigge   spi/pl022: Add ch...
461
462
  static void pl022_cs_control(struct pl022 *pl022, u32 command)
  {
db4fa45ed   Anders Berg   spi: pl022: Add s...
463
464
465
  	if (pl022->vendor->internal_cs_ctrl)
  		internal_cs_control(pl022, command);
  	else if (gpio_is_valid(pl022->cur_cs))
f6f46de10   Roland Stigge   spi/pl022: Add ch...
466
467
468
469
  		gpio_set_value(pl022->cur_cs, command);
  	else
  		pl022->cur_chip->cs_control(command);
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
470
471
472
473
474
475
476
477
478
  /**
   * giveback - current spi_message is over, schedule next message and call
   * callback of this message. Assumes that caller already
   * set message->status; dma and pio irqs are blocked
   * @pl022: SSP driver private data structure
   */
  static void giveback(struct pl022 *pl022)
  {
  	struct spi_transfer *last_transfer;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
479
  	pl022->next_msg_cs_active = false;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
480

23e2c2aa4   Axel Lin   spi: Use list_las...
481
482
  	last_transfer = list_last_entry(&pl022->cur_msg->transfers,
  					struct spi_transfer, transfer_list);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
483
484
  
  	/* Delay if requested before any change in chip select */
e74dc5c76   Alexandru Ardelean   spi: use new `spi...
485
486
487
488
489
  	/*
  	 * FIXME: This runs in interrupt context.
  	 * Is this really smart?
  	 */
  	spi_transfer_delay_exec(last_transfer);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
490

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
491
  	if (!last_transfer->cs_change) {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
492
  		struct spi_message *next_msg;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
493
494
495
496
  		/*
  		 * cs_change was not set. We can keep the chip select
  		 * enabled if there is message in the queue and it is
  		 * for the same spi device.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
497
498
499
500
501
502
  		 *
  		 * We cannot postpone this until pump_messages, because
  		 * after calling msg->complete (below) the driver that
  		 * sent the current message could be unloaded, which
  		 * could invalidate the cs_control() callback...
  		 */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
503
  		/* get a pointer to the next message, if any */
ffbbdd213   Linus Walleij   spi: create a mes...
504
  		next_msg = spi_get_next_queued_message(pl022->master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
505

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
506
507
508
  		/*
  		 * see if the next and current messages point
  		 * to the same spi device.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
509
  		 */
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
510
  		if (next_msg && next_msg->spi != pl022->cur_msg->spi)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
511
  			next_msg = NULL;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
512
  		if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
513
  			pl022_cs_control(pl022, SSP_CHIP_DESELECT);
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
514
515
  		else
  			pl022->next_msg_cs_active = true;
ffbbdd213   Linus Walleij   spi: create a mes...
516

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
517
  	}
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
518

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
519
520
521
  	pl022->cur_msg = NULL;
  	pl022->cur_transfer = NULL;
  	pl022->cur_chip = NULL;
fd316941c   Virupax Sadashivpetimath   spi/pl022: disabl...
522
523
524
525
  
  	/* disable the SPI/SSP operation */
  	writew((readw(SSP_CR1(pl022->virtbase)) &
  		(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
cd6fa8d2c   Alexander Sverdlin   spi: pl022: Fix r...
526
  	spi_finalize_current_message(pl022->master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  }
  
  /**
   * flush - flush the FIFO to reach a clean state
   * @pl022: SSP driver private data structure
   */
  static int flush(struct pl022 *pl022)
  {
  	unsigned long limit = loops_per_jiffy << 1;
  
  	dev_dbg(&pl022->adev->dev, "flush
  ");
  	do {
  		while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
  			readw(SSP_DR(pl022->virtbase));
  	} while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
543
544
  
  	pl022->exp_fifo_level = 0;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
545
546
547
548
549
550
551
552
553
554
  	return limit;
  }
  
  /**
   * restore_state - Load configuration of current chip
   * @pl022: SSP driver private data structure
   */
  static void restore_state(struct pl022 *pl022)
  {
  	struct chip_data *chip = pl022->cur_chip;
556f4aeb7   Linus Walleij   spi/pl022: fix up...
555
556
557
558
  	if (pl022->vendor->extended_cr)
  		writel(chip->cr0, SSP_CR0(pl022->virtbase));
  	else
  		writew(chip->cr0, SSP_CR0(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
559
560
561
562
563
564
  	writew(chip->cr1, SSP_CR1(pl022->virtbase));
  	writew(chip->dmacr, SSP_DMACR(pl022->virtbase));
  	writew(chip->cpsr, SSP_CPSR(pl022->virtbase));
  	writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
  	writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
565
566
567
568
569
  /*
   * Default SSP Register Values
   */
  #define DEFAULT_SSP_REG_CR0 ( \
  	GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0)	| \
556f4aeb7   Linus Walleij   spi/pl022: fix up...
570
571
572
573
574
575
576
577
578
579
  	GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 4) | \
  	GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
  	GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
  	GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \
  )
  
  /* ST versions have slightly different bit layout */
  #define DEFAULT_SSP_REG_CR0_ST ( \
  	GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0)	| \
  	GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP_ST, 5) | \
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
580
  	GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
ee2b805c8   Linus Walleij   ARM: 5678/1: SSP/...
581
  	GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
556f4aeb7   Linus Walleij   spi/pl022: fix up...
582
583
584
  	GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
  	GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS_ST, 16)	| \
  	GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF_ST, 21) \
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
585
  )
781c7b129   Linus Walleij   spi/pl022: add su...
586
587
588
589
590
591
592
  /* The PL023 version is slightly different again */
  #define DEFAULT_SSP_REG_CR0_ST_PL023 ( \
  	GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0)	| \
  	GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
  	GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
  	GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \
  )
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
593
594
595
596
  #define DEFAULT_SSP_REG_CR1 ( \
  	GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \
  	GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
  	GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
556f4aeb7   Linus Walleij   spi/pl022: fix up...
597
  	GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) \
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
598
  )
556f4aeb7   Linus Walleij   spi/pl022: fix up...
599
600
601
602
603
604
605
606
607
  /* ST versions extend this register to use all 16 bits */
  #define DEFAULT_SSP_REG_CR1_ST ( \
  	DEFAULT_SSP_REG_CR1 | \
  	GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \
  	GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \
  	GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT_ST, 6) |\
  	GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \
  	GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) \
  )
781c7b129   Linus Walleij   spi/pl022: add su...
608
609
610
611
612
613
614
615
616
617
618
619
620
621
  /*
   * The PL023 variant has further differences: no loopback mode, no microwire
   * support, and a new clock feedback delay setting.
   */
  #define DEFAULT_SSP_REG_CR1_ST_PL023 ( \
  	GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
  	GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
  	GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \
  	GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \
  	GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \
  	GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \
  	GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) | \
  	GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \
  )
556f4aeb7   Linus Walleij   spi/pl022: fix up...
622

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
623
  #define DEFAULT_SSP_REG_CPSR ( \
556f4aeb7   Linus Walleij   spi/pl022: fix up...
624
  	GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
625
626
627
628
629
630
  )
  
  #define DEFAULT_SSP_REG_DMACR (\
  	GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \
  	GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \
  )
781c7b129   Linus Walleij   spi/pl022: add su...
631
632
633
634
  /**
   * load_ssp_default_config - Load default configuration for SSP
   * @pl022: SSP driver private data structure
   */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
635
636
  static void load_ssp_default_config(struct pl022 *pl022)
  {
781c7b129   Linus Walleij   spi/pl022: add su...
637
638
639
640
  	if (pl022->vendor->pl023) {
  		writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase));
  		writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase));
  	} else if (pl022->vendor->extended_cr) {
556f4aeb7   Linus Walleij   spi/pl022: fix up...
641
642
643
644
645
646
  		writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase));
  		writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase));
  	} else {
  		writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
  		writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
647
648
649
650
651
  	writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase));
  	writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase));
  	writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
  	writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
  }
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
652
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
653
654
655
656
657
658
659
   * This will write to TX and read from RX according to the parameters
   * set in pl022.
   */
  static void readwriter(struct pl022 *pl022)
  {
  
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
660
  	 * The FIFO depth is different between primecell variants.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
661
662
663
664
  	 * I believe filling in too much in the FIFO might cause
  	 * errons in 8bit wide transfers on ARM variants (just 8 words
  	 * FIFO, means only 8x8 = 64 bits in FIFO) at least.
  	 *
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
665
666
667
  	 * To prevent this issue, the TX FIFO is only filled to the
  	 * unused RX FIFO fill length, regardless of what the TX
  	 * FIFO status flag indicates.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
668
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
  	 */
  	dev_dbg(&pl022->adev->dev,
  		"%s, rx: %p, rxend: %p, tx: %p, txend: %p
  ",
  		__func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end);
  
  	/* Read as much as you can */
  	while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
  	       && (pl022->rx < pl022->rx_end)) {
  		switch (pl022->read) {
  		case READING_NULL:
  			readw(SSP_DR(pl022->virtbase));
  			break;
  		case READING_U8:
  			*(u8 *) (pl022->rx) =
  				readw(SSP_DR(pl022->virtbase)) & 0xFFU;
  			break;
  		case READING_U16:
  			*(u16 *) (pl022->rx) =
  				(u16) readw(SSP_DR(pl022->virtbase));
  			break;
  		case READING_U32:
  			*(u32 *) (pl022->rx) =
  				readl(SSP_DR(pl022->virtbase));
  			break;
  		}
  		pl022->rx += (pl022->cur_chip->n_bytes);
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
695
  		pl022->exp_fifo_level--;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
696
697
  	}
  	/*
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
698
  	 * Write as much as possible up to the RX FIFO size
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
699
  	 */
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
700
  	while ((pl022->exp_fifo_level < pl022->vendor->fifodepth)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  	       && (pl022->tx < pl022->tx_end)) {
  		switch (pl022->write) {
  		case WRITING_NULL:
  			writew(0x0, SSP_DR(pl022->virtbase));
  			break;
  		case WRITING_U8:
  			writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase));
  			break;
  		case WRITING_U16:
  			writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase));
  			break;
  		case WRITING_U32:
  			writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase));
  			break;
  		}
  		pl022->tx += (pl022->cur_chip->n_bytes);
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
717
  		pl022->exp_fifo_level++;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
718
719
720
721
  		/*
  		 * This inner reader takes care of things appearing in the RX
  		 * FIFO as we're transmitting. This will happen a lot since the
  		 * clock starts running when you put things into the TX FIFO,
25985edce   Lucas De Marchi   Fix common misspe...
722
  		 * and then things are continuously clocked into the RX FIFO.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  		 */
  		while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
  		       && (pl022->rx < pl022->rx_end)) {
  			switch (pl022->read) {
  			case READING_NULL:
  				readw(SSP_DR(pl022->virtbase));
  				break;
  			case READING_U8:
  				*(u8 *) (pl022->rx) =
  					readw(SSP_DR(pl022->virtbase)) & 0xFFU;
  				break;
  			case READING_U16:
  				*(u16 *) (pl022->rx) =
  					(u16) readw(SSP_DR(pl022->virtbase));
  				break;
  			case READING_U32:
  				*(u32 *) (pl022->rx) =
  					readl(SSP_DR(pl022->virtbase));
  				break;
  			}
  			pl022->rx += (pl022->cur_chip->n_bytes);
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
744
  			pl022->exp_fifo_level--;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
745
746
747
748
749
750
751
  		}
  	}
  	/*
  	 * When we exit here the TX FIFO should be full and the RX FIFO
  	 * should be empty
  	 */
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  /**
   * next_transfer - Move to the Next transfer in the current spi message
   * @pl022: SSP driver private data structure
   *
   * This function moves though the linked list of spi transfers in the
   * current spi message and returns with the state of current spi
   * message i.e whether its last transfer is done(STATE_DONE) or
   * Next transfer is ready(STATE_RUNNING)
   */
  static void *next_transfer(struct pl022 *pl022)
  {
  	struct spi_message *msg = pl022->cur_msg;
  	struct spi_transfer *trans = pl022->cur_transfer;
  
  	/* Move to next transfer */
  	if (trans->transfer_list.next != &msg->transfers) {
  		pl022->cur_transfer =
  		    list_entry(trans->transfer_list.next,
  			       struct spi_transfer, transfer_list);
  		return STATE_RUNNING;
  	}
  	return STATE_DONE;
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
775
776
777
778
779
780
781
782
783
  
  /*
   * This DMA functionality is only compiled in if we have
   * access to the generic DMA devices/DMA engine.
   */
  #ifdef CONFIG_DMA_ENGINE
  static void unmap_free_dma_scatter(struct pl022 *pl022)
  {
  	/* Unmap and free the SG tables */
b72988968   Linus Walleij   spi/pl022: map th...
784
  	dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
785
  		     pl022->sgt_tx.nents, DMA_TO_DEVICE);
b72988968   Linus Walleij   spi/pl022: map th...
786
  	dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
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
832
833
834
835
836
837
838
  		     pl022->sgt_rx.nents, DMA_FROM_DEVICE);
  	sg_free_table(&pl022->sgt_rx);
  	sg_free_table(&pl022->sgt_tx);
  }
  
  static void dma_callback(void *data)
  {
  	struct pl022 *pl022 = data;
  	struct spi_message *msg = pl022->cur_msg;
  
  	BUG_ON(!pl022->sgt_rx.sgl);
  
  #ifdef VERBOSE_DEBUG
  	/*
  	 * Optionally dump out buffers to inspect contents, this is
  	 * good if you want to convince yourself that the loopback
  	 * read/write contents are the same, when adopting to a new
  	 * DMA engine.
  	 */
  	{
  		struct scatterlist *sg;
  		unsigned int i;
  
  		dma_sync_sg_for_cpu(&pl022->adev->dev,
  				    pl022->sgt_rx.sgl,
  				    pl022->sgt_rx.nents,
  				    DMA_FROM_DEVICE);
  
  		for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) {
  			dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i);
  			print_hex_dump(KERN_ERR, "SPI RX: ",
  				       DUMP_PREFIX_OFFSET,
  				       16,
  				       1,
  				       sg_virt(sg),
  				       sg_dma_len(sg),
  				       1);
  		}
  		for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) {
  			dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i);
  			print_hex_dump(KERN_ERR, "SPI TX: ",
  				       DUMP_PREFIX_OFFSET,
  				       16,
  				       1,
  				       sg_virt(sg),
  				       sg_dma_len(sg),
  				       1);
  		}
  	}
  #endif
  
  	unmap_free_dma_scatter(pl022);
25985edce   Lucas De Marchi   Fix common misspe...
839
  	/* Update total bytes transferred */
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
840
  	msg->actual_length += pl022->cur_transfer->len;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
841
842
  	/* Move to next transfer */
  	msg->state = next_transfer(pl022);
c0b07605f   Fredrik Ternerot   spi: pl022: Handl...
843
844
  	if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change)
  		pl022_cs_control(pl022, SSP_CHIP_DESELECT);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
  	tasklet_schedule(&pl022->pump_transfers);
  }
  
  static void setup_dma_scatter(struct pl022 *pl022,
  			      void *buffer,
  			      unsigned int length,
  			      struct sg_table *sgtab)
  {
  	struct scatterlist *sg;
  	int bytesleft = length;
  	void *bufp = buffer;
  	int mapbytes;
  	int i;
  
  	if (buffer) {
  		for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
  			/*
  			 * If there are less bytes left than what fits
  			 * in the current page (plus page alignment offset)
  			 * we just feed in this, else we stuff in as much
  			 * as we can.
  			 */
  			if (bytesleft < (PAGE_SIZE - offset_in_page(bufp)))
  				mapbytes = bytesleft;
  			else
  				mapbytes = PAGE_SIZE - offset_in_page(bufp);
  			sg_set_page(sg, virt_to_page(bufp),
  				    mapbytes, offset_in_page(bufp));
  			bufp += mapbytes;
  			bytesleft -= mapbytes;
  			dev_dbg(&pl022->adev->dev,
  				"set RX/TX target page @ %p, %d bytes, %d left
  ",
  				bufp, mapbytes, bytesleft);
  		}
  	} else {
  		/* Map the dummy buffer on every page */
  		for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
  			if (bytesleft < PAGE_SIZE)
  				mapbytes = bytesleft;
  			else
  				mapbytes = PAGE_SIZE;
  			sg_set_page(sg, virt_to_page(pl022->dummypage),
  				    mapbytes, 0);
  			bytesleft -= mapbytes;
  			dev_dbg(&pl022->adev->dev,
  				"set RX/TX to dummy page %d bytes, %d left
  ",
  				mapbytes, bytesleft);
  
  		}
  	}
  	BUG_ON(bytesleft);
  }
  
  /**
   * configure_dma - configures the channels for the next transfer
   * @pl022: SSP driver's private data structure
   */
  static int configure_dma(struct pl022 *pl022)
  {
  	struct dma_slave_config rx_conf = {
  		.src_addr = SSP_DR(pl022->phybase),
a485df4b4   Vinod Koul   spi, serial: move...
908
  		.direction = DMA_DEV_TO_MEM,
258aea76f   Viresh Kumar   dmaengine: Pass d...
909
  		.device_fc = false,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
910
911
912
  	};
  	struct dma_slave_config tx_conf = {
  		.dst_addr = SSP_DR(pl022->phybase),
a485df4b4   Vinod Koul   spi, serial: move...
913
  		.direction = DMA_MEM_TO_DEV,
258aea76f   Viresh Kumar   dmaengine: Pass d...
914
  		.device_fc = false,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
915
916
917
  	};
  	unsigned int pages;
  	int ret;
082086f2c   Linus Walleij   spi/pl022: pass t...
918
  	int rx_sglen, tx_sglen;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
919
920
921
922
  	struct dma_chan *rxchan = pl022->dma_rx_channel;
  	struct dma_chan *txchan = pl022->dma_tx_channel;
  	struct dma_async_tx_descriptor *rxdesc;
  	struct dma_async_tx_descriptor *txdesc;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
923
924
925
926
  
  	/* Check that the channels are available */
  	if (!rxchan || !txchan)
  		return -ENODEV;
083be3f05   Linus Walleij   spi/pl022: initia...
927
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
  	/*
  	 * If supplied, the DMA burstsize should equal the FIFO trigger level.
  	 * Notice that the DMA engine uses one-to-one mapping. Since we can
  	 * not trigger on 2 elements this needs explicit mapping rather than
  	 * calculation.
  	 */
  	switch (pl022->rx_lev_trig) {
  	case SSP_RX_1_OR_MORE_ELEM:
  		rx_conf.src_maxburst = 1;
  		break;
  	case SSP_RX_4_OR_MORE_ELEM:
  		rx_conf.src_maxburst = 4;
  		break;
  	case SSP_RX_8_OR_MORE_ELEM:
  		rx_conf.src_maxburst = 8;
  		break;
  	case SSP_RX_16_OR_MORE_ELEM:
  		rx_conf.src_maxburst = 16;
  		break;
  	case SSP_RX_32_OR_MORE_ELEM:
  		rx_conf.src_maxburst = 32;
  		break;
  	default:
  		rx_conf.src_maxburst = pl022->vendor->fifodepth >> 1;
  		break;
  	}
  
  	switch (pl022->tx_lev_trig) {
  	case SSP_TX_1_OR_MORE_EMPTY_LOC:
  		tx_conf.dst_maxburst = 1;
  		break;
  	case SSP_TX_4_OR_MORE_EMPTY_LOC:
  		tx_conf.dst_maxburst = 4;
  		break;
  	case SSP_TX_8_OR_MORE_EMPTY_LOC:
  		tx_conf.dst_maxburst = 8;
  		break;
  	case SSP_TX_16_OR_MORE_EMPTY_LOC:
  		tx_conf.dst_maxburst = 16;
  		break;
  	case SSP_TX_32_OR_MORE_EMPTY_LOC:
  		tx_conf.dst_maxburst = 32;
  		break;
  	default:
  		tx_conf.dst_maxburst = pl022->vendor->fifodepth >> 1;
  		break;
  	}
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
  	switch (pl022->read) {
  	case READING_NULL:
  		/* Use the same as for writing */
  		rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
  		break;
  	case READING_U8:
  		rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
  		break;
  	case READING_U16:
  		rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  		break;
  	case READING_U32:
  		rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
  		break;
  	}
  
  	switch (pl022->write) {
  	case WRITING_NULL:
  		/* Use the same as for reading */
  		tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
  		break;
  	case WRITING_U8:
  		tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
  		break;
  	case WRITING_U16:
  		tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  		break;
  	case WRITING_U32:
bc3f67a3e   Joe Perches   drivers/spi: Remo...
1002
  		tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1003
1004
1005
1006
1007
1008
1009
1010
1011
  		break;
  	}
  
  	/* SPI pecularity: we need to read and write the same width */
  	if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
  		rx_conf.src_addr_width = tx_conf.dst_addr_width;
  	if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
  		tx_conf.dst_addr_width = rx_conf.src_addr_width;
  	BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width);
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1012
1013
  	dmaengine_slave_config(rxchan, &rx_conf);
  	dmaengine_slave_config(txchan, &tx_conf);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1014
1015
  
  	/* Create sglists for the transfers */
b181565ee   Viresh Kumar   spi/spi-pl022: Do...
1016
  	pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1017
1018
  	dev_dbg(&pl022->adev->dev, "using %d pages for transfer
  ", pages);
538a18dc1   Viresh Kumar   spi/spi-pl022: Us...
1019
  	ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1020
1021
  	if (ret)
  		goto err_alloc_rx_sg;
538a18dc1   Viresh Kumar   spi/spi-pl022: Us...
1022
  	ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
  	if (ret)
  		goto err_alloc_tx_sg;
  
  	/* Fill in the scatterlists for the RX+TX buffers */
  	setup_dma_scatter(pl022, pl022->rx,
  			  pl022->cur_transfer->len, &pl022->sgt_rx);
  	setup_dma_scatter(pl022, pl022->tx,
  			  pl022->cur_transfer->len, &pl022->sgt_tx);
  
  	/* Map DMA buffers */
082086f2c   Linus Walleij   spi/pl022: pass t...
1033
  	rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1034
  			   pl022->sgt_rx.nents, DMA_FROM_DEVICE);
082086f2c   Linus Walleij   spi/pl022: pass t...
1035
  	if (!rx_sglen)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1036
  		goto err_rx_sgmap;
082086f2c   Linus Walleij   spi/pl022: pass t...
1037
  	tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1038
  			   pl022->sgt_tx.nents, DMA_TO_DEVICE);
082086f2c   Linus Walleij   spi/pl022: pass t...
1039
  	if (!tx_sglen)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1040
1041
1042
  		goto err_tx_sgmap;
  
  	/* Send both scatterlists */
16052827d   Alexandre Bounine   dmaengine/dma_sla...
1043
  	rxdesc = dmaengine_prep_slave_sg(rxchan,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1044
  				      pl022->sgt_rx.sgl,
082086f2c   Linus Walleij   spi/pl022: pass t...
1045
  				      rx_sglen,
a485df4b4   Vinod Koul   spi, serial: move...
1046
  				      DMA_DEV_TO_MEM,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1047
1048
1049
  				      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
  	if (!rxdesc)
  		goto err_rxdesc;
16052827d   Alexandre Bounine   dmaengine/dma_sla...
1050
  	txdesc = dmaengine_prep_slave_sg(txchan,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1051
  				      pl022->sgt_tx.sgl,
082086f2c   Linus Walleij   spi/pl022: pass t...
1052
  				      tx_sglen,
a485df4b4   Vinod Koul   spi, serial: move...
1053
  				      DMA_MEM_TO_DEV,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1054
1055
1056
1057
1058
1059
1060
1061
1062
  				      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
  	if (!txdesc)
  		goto err_txdesc;
  
  	/* Put the callback on the RX transfer only, that should finish last */
  	rxdesc->callback = dma_callback;
  	rxdesc->callback_param = pl022;
  
  	/* Submit and fire RX and TX with TX last so we're ready to read! */
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1063
1064
1065
1066
  	dmaengine_submit(rxdesc);
  	dmaengine_submit(txdesc);
  	dma_async_issue_pending(rxchan);
  	dma_async_issue_pending(txchan);
ffbbdd213   Linus Walleij   spi: create a mes...
1067
  	pl022->dma_running = true;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1068
1069
  
  	return 0;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1070
  err_txdesc:
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1071
  	dmaengine_terminate_all(txchan);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1072
  err_rxdesc:
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1073
  	dmaengine_terminate_all(rxchan);
b72988968   Linus Walleij   spi/pl022: map th...
1074
  	dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1075
1076
  		     pl022->sgt_tx.nents, DMA_TO_DEVICE);
  err_tx_sgmap:
b72988968   Linus Walleij   spi/pl022: map th...
1077
  	dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
3ffa6158f   Ray Jui   spi: pl022: Fix i...
1078
  		     pl022->sgt_rx.nents, DMA_FROM_DEVICE);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1079
1080
1081
1082
1083
1084
1085
  err_rx_sgmap:
  	sg_free_table(&pl022->sgt_tx);
  err_alloc_tx_sg:
  	sg_free_table(&pl022->sgt_rx);
  err_alloc_rx_sg:
  	return -ENOMEM;
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
1086
  static int pl022_dma_probe(struct pl022 *pl022)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  {
  	dma_cap_mask_t mask;
  
  	/* Try to acquire a generic DMA engine slave channel */
  	dma_cap_zero(mask);
  	dma_cap_set(DMA_SLAVE, mask);
  	/*
  	 * We need both RX and TX channels to do DMA, else do none
  	 * of them.
  	 */
  	pl022->dma_rx_channel = dma_request_channel(mask,
  					    pl022->master_info->dma_filter,
  					    pl022->master_info->dma_rx_param);
  	if (!pl022->dma_rx_channel) {
43c640157   Viresh Kumar   spi/amba-pl022: w...
1101
1102
  		dev_dbg(&pl022->adev->dev, "no RX DMA channel!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1103
1104
1105
1106
1107
1108
1109
  		goto err_no_rxchan;
  	}
  
  	pl022->dma_tx_channel = dma_request_channel(mask,
  					    pl022->master_info->dma_filter,
  					    pl022->master_info->dma_tx_param);
  	if (!pl022->dma_tx_channel) {
43c640157   Viresh Kumar   spi/amba-pl022: w...
1110
1111
  		dev_dbg(&pl022->adev->dev, "no TX DMA channel!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1112
1113
1114
1115
  		goto err_no_txchan;
  	}
  
  	pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
77538f4a9   Jingoo Han   spi: pl022: remov...
1116
  	if (!pl022->dummypage)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1117
  		goto err_no_dummypage;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  
  	dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s
  ",
  		 dma_chan_name(pl022->dma_rx_channel),
  		 dma_chan_name(pl022->dma_tx_channel));
  
  	return 0;
  
  err_no_dummypage:
  	dma_release_channel(pl022->dma_tx_channel);
  err_no_txchan:
  	dma_release_channel(pl022->dma_rx_channel);
  	pl022->dma_rx_channel = NULL;
  err_no_rxchan:
43c640157   Viresh Kumar   spi/amba-pl022: w...
1132
1133
1134
  	dev_err(&pl022->adev->dev,
  			"Failed to work in dma mode, work without dma!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1135
1136
  	return -ENODEV;
  }
dc715452e   Arnd Bergmann   spi: pl022: use g...
1137
1138
1139
  static int pl022_dma_autoprobe(struct pl022 *pl022)
  {
  	struct device *dev = &pl022->adev->dev;
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1140
1141
  	struct dma_chan *chan;
  	int err;
dc715452e   Arnd Bergmann   spi: pl022: use g...
1142
1143
  
  	/* automatically configure DMA channels from platform, normally using DT */
c1008957f   Peter Ujfalusi   spi: pl022: Use d...
1144
  	chan = dma_request_chan(dev, "rx");
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1145
1146
  	if (IS_ERR(chan)) {
  		err = PTR_ERR(chan);
dc715452e   Arnd Bergmann   spi: pl022: use g...
1147
  		goto err_no_rxchan;
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1148
1149
1150
  	}
  
  	pl022->dma_rx_channel = chan;
dc715452e   Arnd Bergmann   spi: pl022: use g...
1151

c1008957f   Peter Ujfalusi   spi: pl022: Use d...
1152
  	chan = dma_request_chan(dev, "tx");
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1153
1154
  	if (IS_ERR(chan)) {
  		err = PTR_ERR(chan);
dc715452e   Arnd Bergmann   spi: pl022: use g...
1155
  		goto err_no_txchan;
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1156
1157
1158
  	}
  
  	pl022->dma_tx_channel = chan;
dc715452e   Arnd Bergmann   spi: pl022: use g...
1159
1160
  
  	pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1161
1162
  	if (!pl022->dummypage) {
  		err = -ENOMEM;
dc715452e   Arnd Bergmann   spi: pl022: use g...
1163
  		goto err_no_dummypage;
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1164
  	}
dc715452e   Arnd Bergmann   spi: pl022: use g...
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
  
  	return 0;
  
  err_no_dummypage:
  	dma_release_channel(pl022->dma_tx_channel);
  	pl022->dma_tx_channel = NULL;
  err_no_txchan:
  	dma_release_channel(pl022->dma_rx_channel);
  	pl022->dma_rx_channel = NULL;
  err_no_rxchan:
f3d4bb334   Rabin Vincent   spi: pl022: handl...
1175
  	return err;
dc715452e   Arnd Bergmann   spi: pl022: use g...
1176
1177
  }
  		
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1178
1179
1180
1181
  static void terminate_dma(struct pl022 *pl022)
  {
  	struct dma_chan *rxchan = pl022->dma_rx_channel;
  	struct dma_chan *txchan = pl022->dma_tx_channel;
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1182
1183
  	dmaengine_terminate_all(rxchan);
  	dmaengine_terminate_all(txchan);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1184
  	unmap_free_dma_scatter(pl022);
ffbbdd213   Linus Walleij   spi: create a mes...
1185
  	pl022->dma_running = false;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1186
1187
1188
1189
  }
  
  static void pl022_dma_remove(struct pl022 *pl022)
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1190
  	if (pl022->dma_running)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
  		terminate_dma(pl022);
  	if (pl022->dma_tx_channel)
  		dma_release_channel(pl022->dma_tx_channel);
  	if (pl022->dma_rx_channel)
  		dma_release_channel(pl022->dma_rx_channel);
  	kfree(pl022->dummypage);
  }
  
  #else
  static inline int configure_dma(struct pl022 *pl022)
  {
  	return -ENODEV;
  }
dc715452e   Arnd Bergmann   spi: pl022: use g...
1204
1205
1206
1207
  static inline int pl022_dma_autoprobe(struct pl022 *pl022)
  {
  	return 0;
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1208
1209
1210
1211
1212
1213
1214
1215
1216
  static inline int pl022_dma_probe(struct pl022 *pl022)
  {
  	return 0;
  }
  
  static inline void pl022_dma_remove(struct pl022 *pl022)
  {
  }
  #endif
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1217
1218
  /**
   * pl022_interrupt_handler - Interrupt handler for SSP controller
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
1219
1220
   * @irq: IRQ number
   * @dev_id: Local device data
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
   *
   * This function handles interrupts generated for an interrupt based transfer.
   * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the
   * current message's state as STATE_ERROR and schedule the tasklet
   * pump_transfers which will do the postprocessing of the current message by
   * calling giveback(). Otherwise it reads data from RX FIFO till there is no
   * more data, and writes data in TX FIFO till it is not full. If we complete
   * the transfer we move to the next transfer and schedule the tasklet.
   */
  static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
  {
  	struct pl022 *pl022 = dev_id;
  	struct spi_message *msg = pl022->cur_msg;
  	u16 irq_status = 0;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  
  	if (unlikely(!msg)) {
  		dev_err(&pl022->adev->dev,
  			"bad message state in interrupt handler");
  		/* Never fail */
  		return IRQ_HANDLED;
  	}
  
  	/* Read the Interrupt Status Register */
  	irq_status = readw(SSP_MIS(pl022->virtbase));
  
  	if (unlikely(!irq_status))
  		return IRQ_NONE;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1248
1249
1250
1251
1252
  	/*
  	 * This handles the FIFO interrupts, the timeout
  	 * interrupts are flatly ignored, they cannot be
  	 * trusted.
  	 */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1253
1254
1255
1256
1257
  	if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) {
  		/*
  		 * Overrun interrupt - bail out since our Data has been
  		 * corrupted
  		 */
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1258
1259
  		dev_err(&pl022->adev->dev, "FIFO overrun
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1260
1261
1262
1263
  		if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
  			dev_err(&pl022->adev->dev,
  				"RXFIFO is full
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  
  		/*
  		 * Disable and clear interrupts, disable SSP,
  		 * mark message with bad status so it can be
  		 * retried.
  		 */
  		writew(DISABLE_ALL_INTERRUPTS,
  		       SSP_IMSC(pl022->virtbase));
  		writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
  		writew((readw(SSP_CR1(pl022->virtbase)) &
  			(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
  		msg->state = STATE_ERROR;
  
  		/* Schedule message queue handler */
  		tasklet_schedule(&pl022->pump_transfers);
  		return IRQ_HANDLED;
  	}
  
  	readwriter(pl022);
7183d1ebd   Alexander Sverdlin   spi: pl022: Remov...
1283
  	if (pl022->tx == pl022->tx_end) {
172289df4   Chris Blair   spi/pl022: only e...
1284
1285
1286
  		/* Disable Transmit interrupt, enable receive interrupt */
  		writew((readw(SSP_IMSC(pl022->virtbase)) &
  		       ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
  		       SSP_IMSC(pl022->virtbase));
  	}
  
  	/*
  	 * Since all transactions must write as much as shall be read,
  	 * we can conclude the entire transaction once RX is complete.
  	 * At this point, all TX will always be finished.
  	 */
  	if (pl022->rx >= pl022->rx_end) {
  		writew(DISABLE_ALL_INTERRUPTS,
  		       SSP_IMSC(pl022->virtbase));
  		writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
  		if (unlikely(pl022->rx > pl022->rx_end)) {
  			dev_warn(&pl022->adev->dev, "read %u surplus "
  				 "bytes (did you request an odd "
  				 "number of bytes on a 16bit bus?)
  ",
  				 (u32) (pl022->rx - pl022->rx_end));
  		}
25985edce   Lucas De Marchi   Fix common misspe...
1306
  		/* Update total bytes transferred */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1307
  		msg->actual_length += pl022->cur_transfer->len;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1308
1309
  		/* Move to next transfer */
  		msg->state = next_transfer(pl022);
c0b07605f   Fredrik Ternerot   spi: pl022: Handl...
1310
1311
  		if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change)
  			pl022_cs_control(pl022, SSP_CHIP_DESELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1312
1313
1314
1315
1316
1317
  		tasklet_schedule(&pl022->pump_transfers);
  		return IRQ_HANDLED;
  	}
  
  	return IRQ_HANDLED;
  }
c7cd1dfbd   Lee Jones   spi: spi-pl022: P...
1318
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
   * This sets up the pointers to memory for the next message to
   * send out on the SPI bus.
   */
  static int set_up_next_transfer(struct pl022 *pl022,
  				struct spi_transfer *transfer)
  {
  	int residue;
  
  	/* Sanity check the message for this bus width */
  	residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes;
  	if (unlikely(residue != 0)) {
  		dev_err(&pl022->adev->dev,
  			"message of %u bytes to transmit but the current "
  			"chip bus has a data width of %u bytes!
  ",
  			pl022->cur_transfer->len,
  			pl022->cur_chip->n_bytes);
  		dev_err(&pl022->adev->dev, "skipping this message
  ");
  		return -EIO;
  	}
  	pl022->tx = (void *)transfer->tx_buf;
  	pl022->tx_end = pl022->tx + pl022->cur_transfer->len;
  	pl022->rx = (void *)transfer->rx_buf;
  	pl022->rx_end = pl022->rx + pl022->cur_transfer->len;
  	pl022->write =
  	    pl022->tx ? pl022->cur_chip->write : WRITING_NULL;
  	pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL;
  	return 0;
  }
  
  /**
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1351
1352
   * pump_transfers - Tasklet function which schedules next transfer
   * when running in interrupt or DMA transfer mode.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
   * @data: SSP driver private data structure
   *
   */
  static void pump_transfers(unsigned long data)
  {
  	struct pl022 *pl022 = (struct pl022 *) data;
  	struct spi_message *message = NULL;
  	struct spi_transfer *transfer = NULL;
  	struct spi_transfer *previous = NULL;
  
  	/* Get current state information */
  	message = pl022->cur_msg;
  	transfer = pl022->cur_transfer;
  
  	/* Handle for abort */
  	if (message->state == STATE_ERROR) {
  		message->status = -EIO;
  		giveback(pl022);
  		return;
  	}
  
  	/* Handle end of message */
  	if (message->state == STATE_DONE) {
  		message->status = 0;
  		giveback(pl022);
  		return;
  	}
  
  	/* Delay if requested at end of transfer before CS change */
  	if (message->state == STATE_RUNNING) {
  		previous = list_entry(transfer->transfer_list.prev,
  					struct spi_transfer,
  					transfer_list);
e74dc5c76   Alexandru Ardelean   spi: use new `spi...
1386
1387
1388
1389
1390
  		/*
  		 * FIXME: This runs in interrupt context.
  		 * Is this really smart?
  		 */
  		spi_transfer_delay_exec(previous);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1391

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
1392
  		/* Reselect chip select only if cs_change was requested */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1393
  		if (previous->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1394
  			pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
  	} else {
  		/* STATE_START */
  		message->state = STATE_RUNNING;
  	}
  
  	if (set_up_next_transfer(pl022, transfer)) {
  		message->state = STATE_ERROR;
  		message->status = -EIO;
  		giveback(pl022);
  		return;
  	}
  	/* Flush the FIFOs and let's go! */
  	flush(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1408

b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1409
1410
1411
1412
1413
1414
1415
  	if (pl022->cur_chip->enable_dma) {
  		if (configure_dma(pl022)) {
  			dev_dbg(&pl022->adev->dev,
  				"configuration of DMA failed, fall back to interrupt mode
  ");
  			goto err_config_dma;
  		}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1416
1417
  		return;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1418

b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1419
  err_config_dma:
172289df4   Chris Blair   spi/pl022: only e...
1420
1421
  	/* enable all interrupts except RX */
  	writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1422
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1423
  static void do_interrupt_dma_transfer(struct pl022 *pl022)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1424
  {
172289df4   Chris Blair   spi/pl022: only e...
1425
1426
1427
1428
  	/*
  	 * Default is to enable all interrupts except RX -
  	 * this will be enabled once TX is complete
  	 */
d555ea05f   Mark Brown   spi/pl022: Explic...
1429
  	u32 irqflags = (u32)(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1430

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
1431
1432
  	/* Enable target chip, if not already active */
  	if (!pl022->next_msg_cs_active)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1433
  		pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1434

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1435
1436
1437
1438
1439
1440
1441
  	if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
  		/* Error path */
  		pl022->cur_msg->state = STATE_ERROR;
  		pl022->cur_msg->status = -EIO;
  		giveback(pl022);
  		return;
  	}
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
  	/* If we're using DMA, set up DMA here */
  	if (pl022->cur_chip->enable_dma) {
  		/* Configure DMA transfer */
  		if (configure_dma(pl022)) {
  			dev_dbg(&pl022->adev->dev,
  				"configuration of DMA failed, fall back to interrupt mode
  ");
  			goto err_config_dma;
  		}
  		/* Disable interrupts in DMA mode, IRQ from DMA controller */
  		irqflags = DISABLE_ALL_INTERRUPTS;
  	}
  err_config_dma:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1455
1456
1457
  	/* Enable SSP, turn on interrupts */
  	writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
  	       SSP_CR1(pl022->virtbase));
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1458
  	writew(irqflags, SSP_IMSC(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1459
  }
7aef2b646   Jiwei Sun   spi: pl022: add a...
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  static void print_current_status(struct pl022 *pl022)
  {
  	u32 read_cr0;
  	u16 read_cr1, read_dmacr, read_sr;
  
  	if (pl022->vendor->extended_cr)
  		read_cr0 = readl(SSP_CR0(pl022->virtbase));
  	else
  		read_cr0 = readw(SSP_CR0(pl022->virtbase));
  	read_cr1 = readw(SSP_CR1(pl022->virtbase));
  	read_dmacr = readw(SSP_DMACR(pl022->virtbase));
  	read_sr = readw(SSP_SR(pl022->virtbase));
  
  	dev_warn(&pl022->adev->dev, "spi-pl022 CR0: %x
  ", read_cr0);
  	dev_warn(&pl022->adev->dev, "spi-pl022 CR1: %x
  ", read_cr1);
  	dev_warn(&pl022->adev->dev, "spi-pl022 DMACR: %x
  ", read_dmacr);
  	dev_warn(&pl022->adev->dev, "spi-pl022 SR: %x
  ", read_sr);
  	dev_warn(&pl022->adev->dev,
  			"spi-pl022 exp_fifo_level/fifodepth: %u/%d
  ",
  			pl022->exp_fifo_level,
  			pl022->vendor->fifodepth);
  
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1488
  static void do_polling_transfer(struct pl022 *pl022)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1489
  {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1490
1491
1492
  	struct spi_message *message = NULL;
  	struct spi_transfer *transfer = NULL;
  	struct spi_transfer *previous = NULL;
a18c266f8   Magnus Templing   spi/pl022: timeou...
1493
  	unsigned long time, timeout;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1494

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  	message = pl022->cur_msg;
  
  	while (message->state != STATE_DONE) {
  		/* Handle for abort */
  		if (message->state == STATE_ERROR)
  			break;
  		transfer = pl022->cur_transfer;
  
  		/* Delay if requested at end of transfer */
  		if (message->state == STATE_RUNNING) {
  			previous =
  			    list_entry(transfer->transfer_list.prev,
  				       struct spi_transfer, transfer_list);
e74dc5c76   Alexandru Ardelean   spi: use new `spi...
1508
  			spi_transfer_delay_exec(previous);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1509
  			if (previous->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1510
  				pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1511
1512
1513
  		} else {
  			/* STATE_START */
  			message->state = STATE_RUNNING;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
1514
  			if (!pl022->next_msg_cs_active)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1515
  				pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
  		}
  
  		/* Configuration Changing Per Transfer */
  		if (set_up_next_transfer(pl022, transfer)) {
  			/* Error path */
  			message->state = STATE_ERROR;
  			break;
  		}
  		/* Flush FIFOs and enable SSP */
  		flush(pl022);
  		writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
  		       SSP_CR1(pl022->virtbase));
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1528
1529
  		dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...
  ");
a18c266f8   Magnus Templing   spi/pl022: timeou...
1530
1531
1532
1533
  
  		timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT);
  		while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) {
  			time = jiffies;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1534
  			readwriter(pl022);
a18c266f8   Magnus Templing   spi/pl022: timeou...
1535
1536
1537
1538
  			if (time_after(time, timeout)) {
  				dev_warn(&pl022->adev->dev,
  				"%s: timeout!
  ", __func__);
7aef2b646   Jiwei Sun   spi: pl022: add a...
1539
1540
  				message->state = STATE_TIMEOUT;
  				print_current_status(pl022);
a18c266f8   Magnus Templing   spi/pl022: timeou...
1541
1542
  				goto out;
  			}
521999bd4   Linus Walleij   spi/pl022: use cp...
1543
  			cpu_relax();
a18c266f8   Magnus Templing   spi/pl022: timeou...
1544
  		}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1545

25985edce   Lucas De Marchi   Fix common misspe...
1546
  		/* Update total byte transferred */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1547
  		message->actual_length += pl022->cur_transfer->len;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1548
1549
  		/* Move to next transfer */
  		message->state = next_transfer(pl022);
c0b07605f   Fredrik Ternerot   spi: pl022: Handl...
1550
1551
1552
  		if (message->state != STATE_DONE
  		    && pl022->cur_transfer->cs_change)
  			pl022_cs_control(pl022, SSP_CHIP_DESELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1553
  	}
a18c266f8   Magnus Templing   spi/pl022: timeou...
1554
  out:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1555
1556
1557
  	/* Handle end of message */
  	if (message->state == STATE_DONE)
  		message->status = 0;
7aef2b646   Jiwei Sun   spi: pl022: add a...
1558
1559
  	else if (message->state == STATE_TIMEOUT)
  		message->status = -EAGAIN;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1560
1561
1562
1563
1564
1565
  	else
  		message->status = -EIO;
  
  	giveback(pl022);
  	return;
  }
ffbbdd213   Linus Walleij   spi: create a mes...
1566
1567
  static int pl022_transfer_one_message(struct spi_master *master,
  				      struct spi_message *msg)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1568
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1569
  	struct pl022 *pl022 = spi_master_get_devdata(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1570
1571
  
  	/* Initial message state */
ffbbdd213   Linus Walleij   spi: create a mes...
1572
1573
1574
1575
1576
  	pl022->cur_msg = msg;
  	msg->state = STATE_START;
  
  	pl022->cur_transfer = list_entry(msg->transfers.next,
  					 struct spi_transfer, transfer_list);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1577
1578
  
  	/* Setup the SPI using the per chip configuration */
ffbbdd213   Linus Walleij   spi: create a mes...
1579
  	pl022->cur_chip = spi_get_ctldata(msg->spi);
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1580
  	pl022->cur_cs = pl022->chipselects[msg->spi->chip_select];
d4b6af2e0   Chris Blair   spi/pl022: move d...
1581

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1582
1583
1584
1585
1586
  	restore_state(pl022);
  	flush(pl022);
  
  	if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
  		do_polling_transfer(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1587
  	else
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1588
  		do_interrupt_dma_transfer(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1589
1590
1591
  
  	return 0;
  }
ffbbdd213   Linus Walleij   spi: create a mes...
1592
  static int pl022_unprepare_transfer_hardware(struct spi_master *master)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1593
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1594
  	struct pl022 *pl022 = spi_master_get_devdata(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1595

ffbbdd213   Linus Walleij   spi: create a mes...
1596
1597
1598
  	/* nothing more to do - disable spi/ssp and power off */
  	writew((readw(SSP_CR1(pl022->virtbase)) &
  		(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1599

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1600
1601
1602
1603
  	return 0;
  }
  
  static int verify_controller_parameters(struct pl022 *pl022,
f9d629c73   Linus Walleij   spi/pl022: fix du...
1604
  				struct pl022_config_chip const *chip_info)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1605
  {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1606
1607
  	if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
  	    || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1608
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1609
1610
1611
1612
1613
1614
  			"interface is configured incorrectly
  ");
  		return -EINVAL;
  	}
  	if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
  	    (!pl022->vendor->unidir)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1615
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1616
1617
1618
1619
1620
1621
1622
  			"unidirectional mode not supported in this "
  			"hardware version
  ");
  		return -EINVAL;
  	}
  	if ((chip_info->hierarchy != SSP_MASTER)
  	    && (chip_info->hierarchy != SSP_SLAVE)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1623
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1624
1625
1626
1627
  			"hierarchy is configured incorrectly
  ");
  		return -EINVAL;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1628
1629
1630
  	if ((chip_info->com_mode != INTERRUPT_TRANSFER)
  	    && (chip_info->com_mode != DMA_TRANSFER)
  	    && (chip_info->com_mode != POLLING_TRANSFER)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1631
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1632
1633
1634
1635
  			"Communication mode is configured incorrectly
  ");
  		return -EINVAL;
  	}
78b2b911b   Linus Walleij   spi/pl022: streng...
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
  	switch (chip_info->rx_lev_trig) {
  	case SSP_RX_1_OR_MORE_ELEM:
  	case SSP_RX_4_OR_MORE_ELEM:
  	case SSP_RX_8_OR_MORE_ELEM:
  		/* These are always OK, all variants can handle this */
  		break;
  	case SSP_RX_16_OR_MORE_ELEM:
  		if (pl022->vendor->fifodepth < 16) {
  			dev_err(&pl022->adev->dev,
  			"RX FIFO Trigger Level is configured incorrectly
  ");
  			return -EINVAL;
  		}
  		break;
  	case SSP_RX_32_OR_MORE_ELEM:
  		if (pl022->vendor->fifodepth < 32) {
  			dev_err(&pl022->adev->dev,
  			"RX FIFO Trigger Level is configured incorrectly
  ");
  			return -EINVAL;
  		}
  		break;
  	default:
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1659
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1660
1661
1662
1663
  			"RX FIFO Trigger Level is configured incorrectly
  ");
  		return -EINVAL;
  	}
78b2b911b   Linus Walleij   spi/pl022: streng...
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  	switch (chip_info->tx_lev_trig) {
  	case SSP_TX_1_OR_MORE_EMPTY_LOC:
  	case SSP_TX_4_OR_MORE_EMPTY_LOC:
  	case SSP_TX_8_OR_MORE_EMPTY_LOC:
  		/* These are always OK, all variants can handle this */
  		break;
  	case SSP_TX_16_OR_MORE_EMPTY_LOC:
  		if (pl022->vendor->fifodepth < 16) {
  			dev_err(&pl022->adev->dev,
  			"TX FIFO Trigger Level is configured incorrectly
  ");
  			return -EINVAL;
  		}
  		break;
  	case SSP_TX_32_OR_MORE_EMPTY_LOC:
  		if (pl022->vendor->fifodepth < 32) {
  			dev_err(&pl022->adev->dev,
  			"TX FIFO Trigger Level is configured incorrectly
  ");
  			return -EINVAL;
  		}
  		break;
  	default:
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1687
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1688
1689
1690
1691
  			"TX FIFO Trigger Level is configured incorrectly
  ");
  		return -EINVAL;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1692
1693
1694
  	if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
  		if ((chip_info->ctrl_len < SSP_BITS_4)
  		    || (chip_info->ctrl_len > SSP_BITS_32)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1695
  			dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1696
1697
1698
1699
1700
1701
  				"CTRL LEN is configured incorrectly
  ");
  			return -EINVAL;
  		}
  		if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO)
  		    && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1702
  			dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1703
1704
1705
1706
  				"Wait State is configured incorrectly
  ");
  			return -EINVAL;
  		}
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1707
1708
1709
1710
1711
  		/* Half duplex is only available in the ST Micro version */
  		if (pl022->vendor->extended_cr) {
  			if ((chip_info->duplex !=
  			     SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
  			    && (chip_info->duplex !=
4a4fd4715   Julia Lawall   spi/amba-pl022: F...
1712
  				SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1713
  				dev_err(&pl022->adev->dev,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1714
1715
1716
  					"Microwire duplex mode is configured incorrectly
  ");
  				return -EINVAL;
4a4fd4715   Julia Lawall   spi/amba-pl022: F...
1717
  			}
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1718
1719
  		} else {
  			if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1720
  				dev_err(&pl022->adev->dev,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1721
1722
1723
1724
  					"Microwire half duplex mode requested,"
  					" but this is only available in the"
  					" ST version of PL022
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1725
1726
1727
  			return -EINVAL;
  		}
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1728
1729
  	return 0;
  }
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1730
1731
1732
1733
1734
1735
1736
  static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
  {
  	return rate / (cpsdvsr * (1 + scr));
  }
  
  static int calculate_effective_freq(struct pl022 *pl022, int freq, struct
  				    ssp_clock_params * clk_freq)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1737
1738
  {
  	/* Lets calculate the frequency parameters */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1739
1740
1741
  	u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN;
  	u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0,
  		best_scr = 0, tmp, found = 0;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1742
1743
1744
  
  	rate = clk_get_rate(pl022->clk);
  	/* cpsdvscr = 2 & scr 0 */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1745
  	max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1746
  	/* cpsdvsr = 254 & scr = 255 */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1747
  	min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
ea505bc99   Viresh Kumar   spi/pl022: Allow ...
1748
1749
1750
1751
1752
1753
1754
  	if (freq > max_tclk)
  		dev_warn(&pl022->adev->dev,
  			"Max speed that can be programmed is %d Hz, you requested %d
  ",
  			max_tclk, freq);
  
  	if (freq < min_tclk) {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1755
  		dev_err(&pl022->adev->dev,
ea505bc99   Viresh Kumar   spi/pl022: Allow ...
1756
1757
1758
  			"Requested frequency: %d Hz is less than minimum possible %d Hz
  ",
  			freq, min_tclk);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1759
1760
  		return -EINVAL;
  	}
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1761
1762
1763
1764
1765
1766
1767
1768
  
  	/*
  	 * best_freq will give closest possible available rate (<= requested
  	 * freq) for all values of scr & cpsdvsr.
  	 */
  	while ((cpsdvsr <= CPSDVR_MAX) && !found) {
  		while (scr <= SCR_MAX) {
  			tmp = spi_rate(rate, cpsdvsr, scr);
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1769
1770
  			if (tmp > freq) {
  				/* we need lower freq */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1771
  				scr++;
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1772
1773
  				continue;
  			}
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1774
  			/*
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1775
1776
  			 * If found exact value, mark found and break.
  			 * If found more closer value, update and break.
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1777
  			 */
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1778
  			if (tmp > best_freq) {
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1779
1780
1781
1782
1783
  				best_freq = tmp;
  				best_cpsdvsr = cpsdvsr;
  				best_scr = scr;
  
  				if (tmp == freq)
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1784
  					found = 1;
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1785
  			}
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1786
1787
1788
1789
1790
  			/*
  			 * increased scr will give lower rates, which are not
  			 * required
  			 */
  			break;
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1791
1792
1793
1794
  		}
  		cpsdvsr += 2;
  		scr = SCR_MIN;
  	}
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1795
1796
1797
  	WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate 
  ",
  			freq);
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1798
1799
1800
1801
1802
1803
1804
1805
1806
  	clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
  	clk_freq->scr = (u8) (best_scr & 0xFF);
  	dev_dbg(&pl022->adev->dev,
  		"SSP Target Frequency is: %u, Effective Frequency is %u
  ",
  		freq, best_freq);
  	dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d
  ",
  		clk_freq->cpsdvsr, clk_freq->scr);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1807
1808
  	return 0;
  }
f9d629c73   Linus Walleij   spi/pl022: fix du...
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
  /*
   * A piece of default chip info unless the platform
   * supplies it.
   */
  static const struct pl022_config_chip pl022_default_chip_info = {
  	.com_mode = POLLING_TRANSFER,
  	.iface = SSP_INTERFACE_MOTOROLA_SPI,
  	.hierarchy = SSP_SLAVE,
  	.slave_tx_disable = DO_NOT_DRIVE_TX,
  	.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
  	.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
  	.ctrl_len = SSP_BITS_8,
  	.wait_state = SSP_MWIRE_WAIT_ZERO,
  	.duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
  	.cs_control = null_cs_control,
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1825
  /**
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
   * pl022_setup - setup function registered to SPI master framework
   * @spi: spi device which is requesting setup
   *
   * This function is registered to the SPI framework for this SPI master
   * controller. If it is the first time when setup is called by this device,
   * this function will initialize the runtime state for this chip and save
   * the same in the device structure. Else it will update the runtime info
   * with the updated chip info. Nothing is really being written to the
   * controller hardware here, that is not done until the actual transfer
   * commence.
   */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1837
1838
  static int pl022_setup(struct spi_device *spi)
  {
f9d629c73   Linus Walleij   spi/pl022: fix du...
1839
  	struct pl022_config_chip const *chip_info;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
1840
  	struct pl022_config_chip chip_info_dt;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1841
  	struct chip_data *chip;
c4a478430   Jonas Aaberg   spi/pl022: fix bu...
1842
  	struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1843
1844
  	int status = 0;
  	struct pl022 *pl022 = spi_master_get_devdata(spi->master);
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1845
1846
  	unsigned int bits = spi->bits_per_word;
  	u32 tmp;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
1847
  	struct device_node *np = spi->dev.of_node;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1848
1849
1850
1851
1852
1853
1854
1855
1856
  
  	if (!spi->max_speed_hz)
  		return -EINVAL;
  
  	/* Get controller_state if one is supplied */
  	chip = spi_get_ctldata(spi);
  
  	if (chip == NULL) {
  		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
77538f4a9   Jingoo Han   spi: pl022: remov...
1857
  		if (!chip)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1858
  			return -ENOMEM;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1859
1860
1861
1862
1863
1864
1865
1866
1867
  		dev_dbg(&spi->dev,
  			"allocated memory for controller's runtime state
  ");
  	}
  
  	/* Get controller data if one is supplied */
  	chip_info = spi->controller_data;
  
  	if (chip_info == NULL) {
6d3952a7d   Roland Stigge   spi/pl022: Add de...
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
  		if (np) {
  			chip_info_dt = pl022_default_chip_info;
  
  			chip_info_dt.hierarchy = SSP_MASTER;
  			of_property_read_u32(np, "pl022,interface",
  				&chip_info_dt.iface);
  			of_property_read_u32(np, "pl022,com-mode",
  				&chip_info_dt.com_mode);
  			of_property_read_u32(np, "pl022,rx-level-trig",
  				&chip_info_dt.rx_lev_trig);
  			of_property_read_u32(np, "pl022,tx-level-trig",
  				&chip_info_dt.tx_lev_trig);
  			of_property_read_u32(np, "pl022,ctrl-len",
  				&chip_info_dt.ctrl_len);
  			of_property_read_u32(np, "pl022,wait-state",
  				&chip_info_dt.wait_state);
  			of_property_read_u32(np, "pl022,duplex",
  				&chip_info_dt.duplex);
  
  			chip_info = &chip_info_dt;
  		} else {
  			chip_info = &pl022_default_chip_info;
  			/* spi_board_info.controller_data not is supplied */
  			dev_dbg(&spi->dev,
  				"using default controller_data settings
  ");
  		}
f9d629c73   Linus Walleij   spi/pl022: fix du...
1895
  	} else
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1896
1897
1898
  		dev_dbg(&spi->dev,
  			"using user supplied controller_data settings
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1899
1900
1901
1902
1903
1904
1905
1906
1907
  
  	/*
  	 * We can override with custom divisors, else we use the board
  	 * frequency setting
  	 */
  	if ((0 == chip_info->clk_freq.cpsdvsr)
  	    && (0 == chip_info->clk_freq.scr)) {
  		status = calculate_effective_freq(pl022,
  						  spi->max_speed_hz,
f9d629c73   Linus Walleij   spi/pl022: fix du...
1908
  						  &clk_freq);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1909
1910
1911
  		if (status < 0)
  			goto err_config_params;
  	} else {
f9d629c73   Linus Walleij   spi/pl022: fix du...
1912
1913
1914
1915
  		memcpy(&clk_freq, &chip_info->clk_freq, sizeof(clk_freq));
  		if ((clk_freq.cpsdvsr % 2) != 0)
  			clk_freq.cpsdvsr =
  				clk_freq.cpsdvsr - 1;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1916
  	}
f9d629c73   Linus Walleij   spi/pl022: fix du...
1917
1918
  	if ((clk_freq.cpsdvsr < CPSDVR_MIN)
  	    || (clk_freq.cpsdvsr > CPSDVR_MAX)) {
e3f88ae99   Virupax Sadashivpetimath   spi-pl022: Add mi...
1919
  		status = -EINVAL;
f9d629c73   Linus Walleij   spi/pl022: fix du...
1920
1921
1922
1923
1924
  		dev_err(&spi->dev,
  			"cpsdvsr is configured incorrectly
  ");
  		goto err_config_params;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1925
1926
1927
1928
1929
  	status = verify_controller_parameters(pl022, chip_info);
  	if (status) {
  		dev_err(&spi->dev, "controller data is incorrect");
  		goto err_config_params;
  	}
f9d629c73   Linus Walleij   spi/pl022: fix du...
1930

083be3f05   Linus Walleij   spi/pl022: initia...
1931
1932
  	pl022->rx_lev_trig = chip_info->rx_lev_trig;
  	pl022->tx_lev_trig = chip_info->tx_lev_trig;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1933
1934
  	/* Now set controller state based on controller data */
  	chip->xfer_type = chip_info->com_mode;
f9d629c73   Linus Walleij   spi/pl022: fix du...
1935
1936
  	if (!chip_info->cs_control) {
  		chip->cs_control = null_cs_control;
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1937
1938
1939
1940
  		if (!gpio_is_valid(pl022->chipselects[spi->chip_select]))
  			dev_warn(&spi->dev,
  				 "invalid chip select
  ");
f9d629c73   Linus Walleij   spi/pl022: fix du...
1941
1942
  	} else
  		chip->cs_control = chip_info->cs_control;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1943

eb798c641   Vinit Shenoy   spi/pl022: Fix ra...
1944
1945
  	/* Check bits per word with vendor specific range */
  	if ((bits <= 3) || (bits > pl022->vendor->max_bpw)) {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1946
  		status = -ENOTSUPP;
eb798c641   Vinit Shenoy   spi/pl022: Fix ra...
1947
1948
1949
1950
1951
  		dev_err(&spi->dev, "illegal data size for this controller!
  ");
  		dev_err(&spi->dev, "This controller can only handle 4 <= n <= %d bit words
  ",
  				pl022->vendor->max_bpw);
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1952
1953
1954
1955
  		goto err_config_params;
  	} else if (bits <= 8) {
  		dev_dbg(&spi->dev, "4 <= n <=8 bits per word
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1956
1957
1958
  		chip->n_bytes = 1;
  		chip->read = READING_U8;
  		chip->write = WRITING_U8;
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1959
  	} else if (bits <= 16) {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1960
1961
1962
1963
1964
1965
  		dev_dbg(&spi->dev, "9 <= n <= 16 bits per word
  ");
  		chip->n_bytes = 2;
  		chip->read = READING_U16;
  		chip->write = WRITING_U16;
  	} else {
eb798c641   Vinit Shenoy   spi/pl022: Fix ra...
1966
1967
1968
1969
1970
  		dev_dbg(&spi->dev, "17 <= n <= 32 bits per word
  ");
  		chip->n_bytes = 4;
  		chip->read = READING_U32;
  		chip->write = WRITING_U32;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1971
1972
1973
1974
1975
1976
1977
1978
1979
  	}
  
  	/* Now Initialize all register settings required for this chip */
  	chip->cr0 = 0;
  	chip->cr1 = 0;
  	chip->dmacr = 0;
  	chip->cpsr = 0;
  	if ((chip_info->com_mode == DMA_TRANSFER)
  	    && ((pl022->master_info)->enable_dma)) {
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1980
  		chip->enable_dma = true;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1981
1982
  		dev_dbg(&spi->dev, "DMA mode set in controller state
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1983
1984
1985
1986
1987
  		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
  			       SSP_DMACR_MASK_RXDMAE, 0);
  		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
  			       SSP_DMACR_MASK_TXDMAE, 1);
  	} else {
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1988
  		chip->enable_dma = false;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1989
1990
1991
1992
1993
1994
1995
  		dev_dbg(&spi->dev, "DMA mode NOT set in controller state
  ");
  		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
  			       SSP_DMACR_MASK_RXDMAE, 0);
  		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
  			       SSP_DMACR_MASK_TXDMAE, 1);
  	}
f9d629c73   Linus Walleij   spi/pl022: fix du...
1996
  	chip->cpsr = clk_freq.cpsdvsr;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1997

556f4aeb7   Linus Walleij   spi/pl022: fix up...
1998
1999
  	/* Special setup for the ST micro extended control registers */
  	if (pl022->vendor->extended_cr) {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2000
  		u32 etx;
781c7b129   Linus Walleij   spi/pl022: add su...
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
  		if (pl022->vendor->pl023) {
  			/* These bits are only in the PL023 */
  			SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay,
  				       SSP_CR1_MASK_FBCLKDEL_ST, 13);
  		} else {
  			/* These bits are in the PL022 but not PL023 */
  			SSP_WRITE_BITS(chip->cr0, chip_info->duplex,
  				       SSP_CR0_MASK_HALFDUP_ST, 5);
  			SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len,
  				       SSP_CR0_MASK_CSS_ST, 16);
  			SSP_WRITE_BITS(chip->cr0, chip_info->iface,
  				       SSP_CR0_MASK_FRF_ST, 21);
  			SSP_WRITE_BITS(chip->cr1, chip_info->wait_state,
  				       SSP_CR1_MASK_MWAIT_ST, 6);
  		}
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2016
  		SSP_WRITE_BITS(chip->cr0, bits - 1,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2017
  			       SSP_CR0_MASK_DSS_ST, 0);
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
  
  		if (spi->mode & SPI_LSB_FIRST) {
  			tmp = SSP_RX_LSB;
  			etx = SSP_TX_LSB;
  		} else {
  			tmp = SSP_RX_MSB;
  			etx = SSP_TX_MSB;
  		}
  		SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4);
  		SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5);
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2028
2029
2030
2031
2032
  		SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig,
  			       SSP_CR1_MASK_RXIFLSEL_ST, 7);
  		SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
  			       SSP_CR1_MASK_TXIFLSEL_ST, 10);
  	} else {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2033
  		SSP_WRITE_BITS(chip->cr0, bits - 1,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2034
2035
2036
2037
  			       SSP_CR0_MASK_DSS, 0);
  		SSP_WRITE_BITS(chip->cr0, chip_info->iface,
  			       SSP_CR0_MASK_FRF, 4);
  	}
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2038

556f4aeb7   Linus Walleij   spi/pl022: fix up...
2039
  	/* Stuff that is common for all versions */
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
  	if (spi->mode & SPI_CPOL)
  		tmp = SSP_CLK_POL_IDLE_HIGH;
  	else
  		tmp = SSP_CLK_POL_IDLE_LOW;
  	SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6);
  
  	if (spi->mode & SPI_CPHA)
  		tmp = SSP_CLK_SECOND_EDGE;
  	else
  		tmp = SSP_CLK_FIRST_EDGE;
  	SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7);
f9d629c73   Linus Walleij   spi/pl022: fix du...
2051
  	SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8);
781c7b129   Linus Walleij   spi/pl022: add su...
2052
  	/* Loopback is available on all versions except PL023 */
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2053
  	if (pl022->vendor->loopback) {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2054
2055
2056
2057
2058
2059
  		if (spi->mode & SPI_LOOP)
  			tmp = LOOPBACK_ENABLED;
  		else
  			tmp = LOOPBACK_DISABLED;
  		SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_LBM, 0);
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2060
2061
  	SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
  	SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
f1e45f86e   Viresh Kumar   spi/spi-pl022: Re...
2062
2063
  	SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD,
  		3);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2064
2065
2066
2067
2068
  
  	/* Save controller_state */
  	spi_set_ctldata(spi, chip);
  	return status;
   err_config_params:
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2069
  	spi_set_ctldata(spi, NULL);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
  	kfree(chip);
  	return status;
  }
  
  /**
   * pl022_cleanup - cleanup function registered to SPI master framework
   * @spi: spi device which is requesting cleanup
   *
   * This function is registered to the SPI framework for this SPI master
   * controller. It will free the runtime state of chip.
   */
  static void pl022_cleanup(struct spi_device *spi)
  {
  	struct chip_data *chip = spi_get_ctldata(spi);
  
  	spi_set_ctldata(spi, NULL);
  	kfree(chip);
  }
39a6ac11d   Roland Stigge   spi/pl022: Device...
2088
2089
2090
2091
2092
  static struct pl022_ssp_controller *
  pl022_platform_data_dt_get(struct device *dev)
  {
  	struct device_node *np = dev->of_node;
  	struct pl022_ssp_controller *pd;
849794c50   Rabin Vincent   spi: pl022: don't...
2093
  	u32 tmp = 0;
39a6ac11d   Roland Stigge   spi/pl022: Device...
2094
2095
2096
2097
2098
2099
2100
2101
  
  	if (!np) {
  		dev_err(dev, "no dt node defined
  ");
  		return NULL;
  	}
  
  	pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
77538f4a9   Jingoo Han   spi: pl022: remov...
2102
  	if (!pd)
39a6ac11d   Roland Stigge   spi/pl022: Device...
2103
  		return NULL;
39a6ac11d   Roland Stigge   spi/pl022: Device...
2104
2105
  
  	pd->bus_id = -1;
dbd897b9c   Linus Walleij   spi: pl022: use D...
2106
  	pd->enable_dma = 1;
39a6ac11d   Roland Stigge   spi/pl022: Device...
2107
2108
2109
2110
2111
2112
2113
2114
  	of_property_read_u32(np, "num-cs", &tmp);
  	pd->num_chipselect = tmp;
  	of_property_read_u32(np, "pl022,autosuspend-delay",
  			     &pd->autosuspend_delay);
  	pd->rt = of_property_read_bool(np, "pl022,rt");
  
  	return pd;
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
2115
  static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2116
2117
  {
  	struct device *dev = &adev->dev;
8074cf063   Jingoo Han   spi: use dev_get_...
2118
2119
  	struct pl022_ssp_controller *platform_info =
  			dev_get_platdata(&adev->dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2120
2121
  	struct spi_master *master;
  	struct pl022 *pl022 = NULL;	/*Data for this driver */
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2122
2123
  	struct device_node *np = adev->dev.of_node;
  	int status = 0, i, num_cs;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2124
2125
2126
2127
  
  	dev_info(&adev->dev,
  		 "ARM PL022 driver, device ID: 0x%08x
  ", adev->periphid);
39a6ac11d   Roland Stigge   spi/pl022: Device...
2128
2129
2130
2131
2132
2133
  	if (!platform_info && IS_ENABLED(CONFIG_OF))
  		platform_info = pl022_platform_data_dt_get(dev);
  
  	if (!platform_info) {
  		dev_err(dev, "probe: no platform data defined
  ");
aeef9915b   Linus Walleij   spi/pl022: use mo...
2134
  		return -ENODEV;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2135
  	}
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2136
2137
  	if (platform_info->num_chipselect) {
  		num_cs = platform_info->num_chipselect;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2138
  	} else {
39a6ac11d   Roland Stigge   spi/pl022: Device...
2139
2140
  		dev_err(dev, "probe: no chip select defined
  ");
aeef9915b   Linus Walleij   spi/pl022: use mo...
2141
  		return -ENODEV;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2142
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2143
  	/* Allocate master with space for data */
b4b848269   Roland Stigge   spi/pl022: Fix ch...
2144
  	master = spi_alloc_master(dev, sizeof(struct pl022));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2145
2146
2147
  	if (master == NULL) {
  		dev_err(&adev->dev, "probe - cannot alloc SPI master
  ");
aeef9915b   Linus Walleij   spi/pl022: use mo...
2148
  		return -ENOMEM;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2149
2150
2151
2152
2153
2154
2155
  	}
  
  	pl022 = spi_master_get_devdata(master);
  	pl022->master = master;
  	pl022->master_info = platform_info;
  	pl022->adev = adev;
  	pl022->vendor = id->data;
a86854d0c   Kees Cook   treewide: devm_kz...
2156
  	pl022->chipselects = devm_kcalloc(dev, num_cs, sizeof(int),
b4b848269   Roland Stigge   spi/pl022: Fix ch...
2157
  					  GFP_KERNEL);
73e3f1eb5   Kiran Padwal   spi: pl022: Add m...
2158
2159
2160
2161
  	if (!pl022->chipselects) {
  		status = -ENOMEM;
  		goto err_no_mem;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2162
2163
2164
2165
2166
2167
  
  	/*
  	 * Bus Number Which has been Assigned to this SSP controller
  	 * on this board
  	 */
  	master->bus_num = platform_info->bus_id;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2168
  	master->num_chipselect = num_cs;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2169
2170
  	master->cleanup = pl022_cleanup;
  	master->setup = pl022_setup;
29b6e906a   Mark Brown   spi/pl022: Conver...
2171
  	master->auto_runtime_pm = true;
ffbbdd213   Linus Walleij   spi: create a mes...
2172
2173
2174
  	master->transfer_one_message = pl022_transfer_one_message;
  	master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
  	master->rt = platform_info->rt;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2175
  	master->dev.of_node = dev->of_node;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2176

6d3952a7d   Roland Stigge   spi/pl022: Add de...
2177
2178
  	if (platform_info->num_chipselect && platform_info->chipselects) {
  		for (i = 0; i < num_cs; i++)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
2179
  			pl022->chipselects[i] = platform_info->chipselects[i];
db4fa45ed   Anders Berg   spi: pl022: Add s...
2180
2181
2182
  	} else if (pl022->vendor->internal_cs_ctrl) {
  		for (i = 0; i < num_cs; i++)
  			pl022->chipselects[i] = i;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
  	} else if (IS_ENABLED(CONFIG_OF)) {
  		for (i = 0; i < num_cs; i++) {
  			int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
  
  			if (cs_gpio == -EPROBE_DEFER) {
  				status = -EPROBE_DEFER;
  				goto err_no_gpio;
  			}
  
  			pl022->chipselects[i] = cs_gpio;
  
  			if (gpio_is_valid(cs_gpio)) {
aeef9915b   Linus Walleij   spi/pl022: use mo...
2195
  				if (devm_gpio_request(dev, cs_gpio, "ssp-pl022"))
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2196
2197
2198
2199
2200
2201
  					dev_err(&adev->dev,
  						"could not request %d gpio
  ",
  						cs_gpio);
  				else if (gpio_direction_output(cs_gpio, 1))
  					dev_err(&adev->dev,
61e89e65e   Roland Stigge   spi/pl022: Fix er...
2202
2203
  						"could not set gpio %d as output
  ",
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2204
2205
2206
2207
  						cs_gpio);
  			}
  		}
  	}
f6f46de10   Roland Stigge   spi/pl022: Add ch...
2208

bde435a9c   Kevin Wells   spi/pl022: Add sp...
2209
2210
2211
2212
2213
2214
2215
  	/*
  	 * Supports mode 0-3, loopback, and active low CS. Transfers are
  	 * always MS bit first on the original pl022.
  	 */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
  	if (pl022->vendor->extended_cr)
  		master->mode_bits |= SPI_LSB_FIRST;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2216
2217
2218
2219
2220
2221
  	dev_dbg(&adev->dev, "BUSNO: %d
  ", master->bus_num);
  
  	status = amba_request_regions(adev, NULL);
  	if (status)
  		goto err_no_ioregion;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
2222
  	pl022->phybase = adev->res.start;
aeef9915b   Linus Walleij   spi/pl022: use mo...
2223
2224
  	pl022->virtbase = devm_ioremap(dev, adev->res.start,
  				       resource_size(&adev->res));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2225
2226
2227
2228
  	if (pl022->virtbase == NULL) {
  		status = -ENOMEM;
  		goto err_no_ioremap;
  	}
2c067509a   Jingoo Han   spi: pl022: Use d...
2229
2230
2231
  	dev_info(&adev->dev, "mapped registers from %pa to %p
  ",
  		&adev->res.start, pl022->virtbase);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2232

aeef9915b   Linus Walleij   spi/pl022: use mo...
2233
  	pl022->clk = devm_clk_get(&adev->dev, NULL);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2234
2235
2236
2237
2238
2239
  	if (IS_ERR(pl022->clk)) {
  		status = PTR_ERR(pl022->clk);
  		dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock
  ");
  		goto err_no_clk;
  	}
7ff6bcf04   Russell King   clk: spi-pl022: c...
2240

6cac167b8   Ulf Hansson   spi: pl022: Simpl...
2241
  	status = clk_prepare_enable(pl022->clk);
71e63e748   Ulf Hansson   ARM: 7149/1: spi/...
2242
2243
2244
2245
2246
  	if (status) {
  		dev_err(&adev->dev, "could not enable SSP/SPI bus clock
  ");
  		goto err_no_clk_en;
  	}
ffbbdd213   Linus Walleij   spi: create a mes...
2247
2248
2249
  	/* Initialize transfer pump */
  	tasklet_init(&pl022->pump_transfers, pump_transfers,
  		     (unsigned long)pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2250
  	/* Disable SSP */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2251
2252
2253
  	writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
  	       SSP_CR1(pl022->virtbase));
  	load_ssp_default_config(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2254

aeef9915b   Linus Walleij   spi/pl022: use mo...
2255
2256
  	status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
  				  0, "pl022", pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2257
2258
2259
2260
2261
  	if (status < 0) {
  		dev_err(&adev->dev, "probe - cannot get IRQ (%d)
  ", status);
  		goto err_no_irq;
  	}
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
2262

dc715452e   Arnd Bergmann   spi: pl022: use g...
2263
2264
  	/* Get DMA channels, try autoconfiguration first */
  	status = pl022_dma_autoprobe(pl022);
f3d4bb334   Rabin Vincent   spi: pl022: handl...
2265
2266
2267
2268
2269
  	if (status == -EPROBE_DEFER) {
  		dev_dbg(dev, "deferring probe to get DMA channel
  ");
  		goto err_no_irq;
  	}
dc715452e   Arnd Bergmann   spi: pl022: use g...
2270
2271
2272
2273
2274
  
  	/* If that failed, use channels from platform_info */
  	if (status == 0)
  		platform_info->enable_dma = 1;
  	else if (platform_info->enable_dma) {
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
2275
2276
  		status = pl022_dma_probe(pl022);
  		if (status != 0)
43c640157   Viresh Kumar   spi/amba-pl022: w...
2277
  			platform_info->enable_dma = 0;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
2278
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2279
2280
  	/* Register with the SPI framework */
  	amba_set_drvdata(adev, pl022);
35794a771   Jingoo Han   spi: pl022: use d...
2281
  	status = devm_spi_register_master(&adev->dev, master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2282
2283
2284
2285
2286
2287
  	if (status != 0) {
  		dev_err(&adev->dev,
  			"probe - problem registering spi master
  ");
  		goto err_spi_register;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
2288
2289
  	dev_dbg(dev, "probe succeeded
  ");
92b97f0aa   Russell King   PM: add runtime P...
2290
2291
  
  	/* let runtime pm put suspend */
53e4acea0   Chris Blair   spi/pl022: add su...
2292
2293
2294
2295
2296
2297
2298
2299
  	if (platform_info->autosuspend_delay > 0) {
  		dev_info(&adev->dev,
  			"will use autosuspend for runtime pm, delay %dms
  ",
  			platform_info->autosuspend_delay);
  		pm_runtime_set_autosuspend_delay(dev,
  			platform_info->autosuspend_delay);
  		pm_runtime_use_autosuspend(dev);
53e4acea0   Chris Blair   spi/pl022: add su...
2300
  	}
0df349945   Ulf Hansson   spi/pl022: Minor ...
2301
  	pm_runtime_put(dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2302
2303
2304
  	return 0;
  
   err_spi_register:
3e3ea7162   Viresh Kumar   spi/spi-pl022: Ca...
2305
2306
  	if (platform_info->enable_dma)
  		pl022_dma_remove(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2307
   err_no_irq:
6cac167b8   Ulf Hansson   spi: pl022: Simpl...
2308
  	clk_disable_unprepare(pl022->clk);
71e63e748   Ulf Hansson   ARM: 7149/1: spi/...
2309
   err_no_clk_en:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2310
   err_no_clk:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2311
2312
2313
   err_no_ioremap:
  	amba_release_regions(adev);
   err_no_ioregion:
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2314
   err_no_gpio:
73e3f1eb5   Kiran Padwal   spi: pl022: Add m...
2315
   err_no_mem:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2316
  	spi_master_put(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2317
2318
  	return status;
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
2319
  static int
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2320
2321
2322
  pl022_remove(struct amba_device *adev)
  {
  	struct pl022 *pl022 = amba_get_drvdata(adev);
50658b660   Linus Walleij   spi/pl022: remove...
2323

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2324
2325
  	if (!pl022)
  		return 0;
92b97f0aa   Russell King   PM: add runtime P...
2326
2327
2328
2329
2330
  	/*
  	 * undo pm_runtime_put() in probe.  I assume that we're not
  	 * accessing the primecell here.
  	 */
  	pm_runtime_get_noresume(&adev->dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2331
  	load_ssp_default_config(pl022);
3e3ea7162   Viresh Kumar   spi/spi-pl022: Ca...
2332
2333
  	if (pl022->master_info->enable_dma)
  		pl022_dma_remove(pl022);
6cac167b8   Ulf Hansson   spi: pl022: Simpl...
2334
  	clk_disable_unprepare(pl022->clk);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2335
2336
  	amba_release_regions(adev);
  	tasklet_disable(&pl022->pump_transfers);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2337
2338
  	return 0;
  }
84a5dc41f   Ulf Hansson   spi: pl022: Don't...
2339
  #ifdef CONFIG_PM_SLEEP
6cfa6279e   Peter Hüwe   ARM: 7079/1: spi:...
2340
  static int pl022_suspend(struct device *dev)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2341
  {
92b97f0aa   Russell King   PM: add runtime P...
2342
  	struct pl022 *pl022 = dev_get_drvdata(dev);
ffbbdd213   Linus Walleij   spi: create a mes...
2343
  	int ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2344

ffbbdd213   Linus Walleij   spi: create a mes...
2345
  	ret = spi_master_suspend(pl022->master);
7c5d8a249   Geert Uytterhoeven   spi: Do not print...
2346
  	if (ret)
ffbbdd213   Linus Walleij   spi: create a mes...
2347
  		return ret;
4964a26df   Ulf Hansson   spi/pl022: Activa...
2348

84a5dc41f   Ulf Hansson   spi: pl022: Don't...
2349
2350
2351
2352
2353
2354
2355
  	ret = pm_runtime_force_suspend(dev);
  	if (ret) {
  		spi_master_resume(pl022->master);
  		return ret;
  	}
  
  	pinctrl_pm_select_sleep_state(dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2356

6cfa6279e   Peter Hüwe   ARM: 7079/1: spi:...
2357
2358
  	dev_dbg(dev, "suspended
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2359
2360
  	return 0;
  }
92b97f0aa   Russell King   PM: add runtime P...
2361
  static int pl022_resume(struct device *dev)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2362
  {
92b97f0aa   Russell King   PM: add runtime P...
2363
  	struct pl022 *pl022 = dev_get_drvdata(dev);
ffbbdd213   Linus Walleij   spi: create a mes...
2364
  	int ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2365

84a5dc41f   Ulf Hansson   spi: pl022: Don't...
2366
2367
2368
2369
  	ret = pm_runtime_force_resume(dev);
  	if (ret)
  		dev_err(dev, "problem resuming
  ");
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2370

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2371
  	/* Start the queue running */
ffbbdd213   Linus Walleij   spi: create a mes...
2372
  	ret = spi_master_resume(pl022->master);
7c5d8a249   Geert Uytterhoeven   spi: Do not print...
2373
  	if (!ret)
92b97f0aa   Russell King   PM: add runtime P...
2374
2375
  		dev_dbg(dev, "resumed
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2376

ffbbdd213   Linus Walleij   spi: create a mes...
2377
  	return ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2378
  }
84a5dc41f   Ulf Hansson   spi: pl022: Don't...
2379
  #endif
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2380

736198b04   Ulf Hansson   spi: pl022: Let r...
2381
  #ifdef CONFIG_PM
92b97f0aa   Russell King   PM: add runtime P...
2382
2383
2384
  static int pl022_runtime_suspend(struct device *dev)
  {
  	struct pl022 *pl022 = dev_get_drvdata(dev);
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
2385

84a5dc41f   Ulf Hansson   spi: pl022: Don't...
2386
2387
  	clk_disable_unprepare(pl022->clk);
  	pinctrl_pm_select_idle_state(dev);
92b97f0aa   Russell King   PM: add runtime P...
2388
2389
2390
2391
2392
2393
  	return 0;
  }
  
  static int pl022_runtime_resume(struct device *dev)
  {
  	struct pl022 *pl022 = dev_get_drvdata(dev);
92b97f0aa   Russell King   PM: add runtime P...
2394

84a5dc41f   Ulf Hansson   spi: pl022: Don't...
2395
2396
  	pinctrl_pm_select_default_state(dev);
  	clk_prepare_enable(pl022->clk);
92b97f0aa   Russell King   PM: add runtime P...
2397
2398
2399
2400
2401
2402
  	return 0;
  }
  #endif
  
  static const struct dev_pm_ops pl022_dev_pm_ops = {
  	SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
6ed23b806   Rafael J. Wysocki   PM: Merge the SET...
2403
  	SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
92b97f0aa   Russell King   PM: add runtime P...
2404
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2405
2406
2407
2408
  static struct vendor_data vendor_arm = {
  	.fifodepth = 8,
  	.max_bpw = 16,
  	.unidir = false,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2409
  	.extended_cr = false,
781c7b129   Linus Walleij   spi/pl022: add su...
2410
  	.pl023 = false,
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2411
  	.loopback = true,
db4fa45ed   Anders Berg   spi: pl022: Add s...
2412
  	.internal_cs_ctrl = false,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2413
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2414
2415
2416
2417
  static struct vendor_data vendor_st = {
  	.fifodepth = 32,
  	.max_bpw = 32,
  	.unidir = false,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2418
  	.extended_cr = true,
781c7b129   Linus Walleij   spi/pl022: add su...
2419
  	.pl023 = false,
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2420
  	.loopback = true,
db4fa45ed   Anders Berg   spi: pl022: Add s...
2421
  	.internal_cs_ctrl = false,
781c7b129   Linus Walleij   spi/pl022: add su...
2422
2423
2424
2425
2426
2427
2428
2429
  };
  
  static struct vendor_data vendor_st_pl023 = {
  	.fifodepth = 32,
  	.max_bpw = 32,
  	.unidir = false,
  	.extended_cr = true,
  	.pl023 = true,
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2430
  	.loopback = false,
db4fa45ed   Anders Berg   spi: pl022: Add s...
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
  	.internal_cs_ctrl = false,
  };
  
  static struct vendor_data vendor_lsi = {
  	.fifodepth = 8,
  	.max_bpw = 16,
  	.unidir = false,
  	.extended_cr = false,
  	.pl023 = false,
  	.loopback = true,
  	.internal_cs_ctrl = true,
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2442
  };
5b8d5ad23   Arvind Yadav   spi: pl022: const...
2443
  static const struct amba_id pl022_ids[] = {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
  	{
  		/*
  		 * ARM PL022 variant, this has a 16bit wide
  		 * and 8 locations deep TX/RX FIFO
  		 */
  		.id	= 0x00041022,
  		.mask	= 0x000fffff,
  		.data	= &vendor_arm,
  	},
  	{
  		/*
  		 * ST Micro derivative, this has 32bit wide
  		 * and 32 locations deep TX/RX FIFO
  		 */
e89e04fcd   Srinidhi Kasagar   ARM: 5741/1: pl02...
2458
  		.id	= 0x01080022,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2459
2460
2461
  		.mask	= 0xffffffff,
  		.data	= &vendor_st,
  	},
781c7b129   Linus Walleij   spi/pl022: add su...
2462
2463
2464
2465
2466
2467
2468
2469
  	{
  		/*
  		 * ST-Ericsson derivative "PL023" (this is not
  		 * an official ARM number), this is a PL022 SSP block
  		 * stripped to SPI mode only, it has 32bit wide
  		 * and 32 locations deep TX/RX FIFO but no extended
  		 * CR0/CR1 register
  		 */
f1e45f86e   Viresh Kumar   spi/spi-pl022: Re...
2470
2471
2472
  		.id	= 0x00080023,
  		.mask	= 0xffffffff,
  		.data	= &vendor_st_pl023,
781c7b129   Linus Walleij   spi/pl022: add su...
2473
  	},
db4fa45ed   Anders Berg   spi: pl022: Add s...
2474
2475
2476
2477
2478
2479
2480
2481
2482
  	{
  		/*
  		 * PL022 variant that has a chip select control register whih
  		 * allows control of 5 output signals nCS[0:4].
  		 */
  		.id	= 0x000b6022,
  		.mask	= 0x000fffff,
  		.data	= &vendor_lsi,
  	},
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2483
2484
  	{ 0, 0 },
  };
7eeac71b9   Dave Martin   spi: pl022: Enabl...
2485
  MODULE_DEVICE_TABLE(amba, pl022_ids);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2486
2487
2488
  static struct amba_driver pl022_driver = {
  	.drv = {
  		.name	= "ssp-pl022",
92b97f0aa   Russell King   PM: add runtime P...
2489
  		.pm	= &pl022_dev_pm_ops,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2490
2491
2492
  	},
  	.id_table	= pl022_ids,
  	.probe		= pl022_probe,
fd4a319bc   Grant Likely   spi: Remove HOTPL...
2493
  	.remove		= pl022_remove,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2494
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2495
2496
2497
2498
  static int __init pl022_init(void)
  {
  	return amba_driver_register(&pl022_driver);
  }
25c8e03bd   Linus Walleij   spi/pl022: move p...
2499
  subsys_initcall(pl022_init);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2500
2501
2502
2503
2504
  
  static void __exit pl022_exit(void)
  {
  	amba_driver_unregister(&pl022_driver);
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2505
2506
2507
2508
2509
  module_exit(pl022_exit);
  
  MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
  MODULE_DESCRIPTION("PL022 SSP Controller Driver");
  MODULE_LICENSE("GPL");