Blame view

drivers/spi/spi-pl022.c 69.8 KB
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2
3
   * A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
   *
aeef9915b   Linus Walleij   spi/pl022: use mo...
4
   * Copyright (C) 2008-2012 ST-Ericsson AB
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   * 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>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
24
25
26
27
28
29
30
  #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...
31
32
33
34
35
36
  #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: ...
37
  #include <linux/slab.h>
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
38
39
40
  #include <linux/dmaengine.h>
  #include <linux/dma-mapping.h>
  #include <linux/scatterlist.h>
bcda6ff8d   Rabin Vincent   spi/pl022: suppor...
41
  #include <linux/pm_runtime.h>
f6f46de10   Roland Stigge   spi/pl022: Add ch...
42
  #include <linux/gpio.h>
6d3952a7d   Roland Stigge   spi/pl022: Add de...
43
  #include <linux/of_gpio.h>
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
44
  #include <linux/pinctrl/consumer.h>
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  
  /*
   * 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)
  #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...
102
103
  #define SSP_CR0_MASK_DSS	(0x0FUL << 0)
  #define SSP_CR0_MASK_FRF	(0x3UL << 4)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
104
105
106
  #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...
107
108
109
110
111
112
113
114
115
  
  /*
   * 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...
116
117
118
119
120
121
122
  /*
   * 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...
123
124
  
  /*
556f4aeb7   Linus Walleij   spi/pl022: fix up...
125
126
   * The ST version of this block adds some bits
   * in SSP_CR1
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
127
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
128
129
130
131
132
  #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...
133
134
  /* This one is only in the PL023 variant */
  #define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
135
136
137
138
139
140
141
  
  /*
   * 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...
142
  #define SSP_SR_MASK_RFF		(0x1UL << 3) /* Receive FIFO full */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
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
191
192
193
194
195
196
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
233
234
  #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)
  
  /*
   * 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...
235
  #define TDR_MASK_TESTDATA		(0xFFFFFFFF)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
236
237
238
239
240
241
242
  
  /*
   * 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...
243
244
245
246
  #define STATE_START			((void *) 0)
  #define STATE_RUNNING			((void *) 1)
  #define STATE_DONE			((void *) 2)
  #define STATE_ERROR			((void *) -1)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
247
248
  
  /*
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
249
250
   * SSP State - Whether Enabled or Disabled
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
251
252
  #define SSP_DISABLED			(0)
  #define SSP_ENABLED			(1)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
253
254
255
256
  
  /*
   * SSP DMA State - Whether DMA Enabled or Disabled
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
257
258
  #define SSP_DMA_DISABLED		(0)
  #define SSP_DMA_ENABLED			(1)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
259
260
261
262
  
  /*
   * SSP Clock Defaults
   */
556f4aeb7   Linus Walleij   spi/pl022: fix up...
263
264
  #define SSP_DEFAULT_CLKRATE 0x2
  #define SSP_DEFAULT_PRESCALE 0x40
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  
  /*
   * 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
  #define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
  
  #define CLEAR_ALL_INTERRUPTS  0x3
a18c266f8   Magnus Templing   spi/pl022: timeou...
282
  #define SPI_POLLING_TIMEOUT 1000
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  /*
   * The type of reading going on on this chip
   */
  enum ssp_reading {
  	READING_NULL,
  	READING_U8,
  	READING_U16,
  	READING_U32
  };
  
  /**
   * 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...
309
310
   * @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...
311
   * @pl023: supports a subset of the ST extensions called "PL023"
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
312
313
314
315
316
   */
  struct vendor_data {
  	int fifodepth;
  	int max_bpw;
  	bool unidir;
556f4aeb7   Linus Walleij   spi/pl022: fix up...
317
  	bool extended_cr;
781c7b129   Linus Walleij   spi/pl022: add su...
318
  	bool pl023;
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
319
  	bool loopback;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
320
321
322
323
324
  };
  
  /**
   * struct pl022 - This is the private SSP driver data structure
   * @adev: AMBA device model hookup
12e8b325f   Linus Walleij   spi/pl022: minor ...
325
326
327
328
   * @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...
329
330
   * @master: SPI framework hookup
   * @master_info: controller-specific data from machine setup
14af60b6f   Chris Blair   spi/pl022: Add hi...
331
332
333
   * @kworker: thread struct for message pump
   * @kworker_task: pointer to task for message pump kworker thread
   * @pump_messages: work struct for scheduling work to the message pump
12e8b325f   Linus Walleij   spi/pl022: minor ...
334
335
   * @queue_lock: spinlock to syncronise access to message queue
   * @queue: message queue
14af60b6f   Chris Blair   spi/pl022: Add hi...
336
337
   * @busy: message pump is busy
   * @running: message pump is running
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
338
339
340
341
   * @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...
342
343
344
345
   * @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...
346
347
348
349
   * @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 ...
350
351
352
353
354
355
356
357
   * @read: the type of read currently going on
   * @write: the type of write currently going on
   * @exp_fifo_level: expected FIFO level
   * @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
f6f46de10   Roland Stigge   spi/pl022: Add ch...
358
359
   * @cur_cs: current chip select (gpio)
   * @chipselects: list of chipselects (gpios)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
360
361
362
363
364
365
366
   */
  struct pl022 {
  	struct amba_device		*adev;
  	struct vendor_data		*vendor;
  	resource_size_t			phybase;
  	void __iomem			*virtbase;
  	struct clk			*clk;
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
367
368
369
  	/* Two optional pin states - default & sleep */
  	struct pinctrl			*pinctrl;
  	struct pinctrl_state		*pins_default;
d8f18420c   Patrice Chotard   spi/pl022: add ID...
370
  	struct pinctrl_state		*pins_idle;
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
371
  	struct pinctrl_state		*pins_sleep;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
372
373
  	struct spi_master		*master;
  	struct pl022_ssp_controller	*master_info;
ffbbdd213   Linus Walleij   spi: create a mes...
374
  	/* Message per-transfer pump */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
375
376
377
378
  	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...
379
  	bool				next_msg_cs_active;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
380
381
382
383
384
385
  	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 ...
386
  	u32				exp_fifo_level;
083be3f05   Linus Walleij   spi/pl022: initia...
387
388
  	enum ssp_rx_level_trig		rx_lev_trig;
  	enum ssp_tx_level_trig		tx_lev_trig;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
389
390
391
392
393
394
395
  	/* 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...
396
  	bool				dma_running;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
397
  #endif
f6f46de10   Roland Stigge   spi/pl022: Add ch...
398
399
  	int cur_cs;
  	int *chipselects;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
400
401
402
403
  };
  
  /**
   * struct chip_data - To maintain runtime state of SSP for each client chip
556f4aeb7   Linus Walleij   spi/pl022: fix up...
404
405
   * @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...
406
407
408
409
410
   * @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...
411
   * @read: function ptr to be used to read when doing xfer for this chip
12e8b325f   Linus Walleij   spi/pl022: minor ...
412
   * @write: function ptr to be used to write when doing xfer for this chip
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
413
414
415
416
417
418
419
   * @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...
420
  	u32 cr0;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
421
422
423
424
  	u16 cr1;
  	u16 dmacr;
  	u16 cpsr;
  	u8 n_bytes;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
425
  	bool enable_dma;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  	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);
  }
f6f46de10   Roland Stigge   spi/pl022: Add ch...
444
445
446
447
448
449
450
  static void pl022_cs_control(struct pl022 *pl022, u32 command)
  {
  	if (gpio_is_valid(pl022->cur_cs))
  		gpio_set_value(pl022->cur_cs, command);
  	else
  		pl022->cur_chip->cs_control(command);
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
451
452
453
454
455
456
457
458
459
  /**
   * 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...
460
  	pl022->next_msg_cs_active = false;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
461

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
462
  	last_transfer = list_entry(pl022->cur_msg->transfers.prev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
463
464
465
466
467
468
469
470
471
472
  					struct spi_transfer,
  					transfer_list);
  
  	/* Delay if requested before any change in chip select */
  	if (last_transfer->delay_usecs)
  		/*
  		 * FIXME: This runs in interrupt context.
  		 * Is this really smart?
  		 */
  		udelay(last_transfer->delay_usecs);
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
473
  	if (!last_transfer->cs_change) {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
474
  		struct spi_message *next_msg;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
475
476
477
478
  		/*
  		 * 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...
479
480
481
482
483
484
  		 *
  		 * 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...
485
  		/* get a pointer to the next message, if any */
ffbbdd213   Linus Walleij   spi: create a mes...
486
  		next_msg = spi_get_next_queued_message(pl022->master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
487

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
488
489
490
  		/*
  		 * see if the next and current messages point
  		 * to the same spi device.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
491
  		 */
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
492
  		if (next_msg && next_msg->spi != pl022->cur_msg->spi)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
493
  			next_msg = NULL;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
494
  		if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
495
  			pl022_cs_control(pl022, SSP_CHIP_DESELECT);
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
496
497
  		else
  			pl022->next_msg_cs_active = true;
ffbbdd213   Linus Walleij   spi: create a mes...
498

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

8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
501
502
503
  	pl022->cur_msg = NULL;
  	pl022->cur_transfer = NULL;
  	pl022->cur_chip = NULL;
ffbbdd213   Linus Walleij   spi: create a mes...
504
  	spi_finalize_current_message(pl022->master);
fd316941c   Virupax Sadashivpetimath   spi/pl022: disabl...
505
506
507
508
  
  	/* disable the SPI/SSP operation */
  	writew((readw(SSP_CR1(pl022->virtbase)) &
  		(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  }
  
  /**
   * 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 ...
525
526
  
  	pl022->exp_fifo_level = 0;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
527
528
529
530
531
532
533
534
535
536
  	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...
537
538
539
540
  	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...
541
542
543
544
545
546
  	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...
547
548
549
550
551
  /*
   * 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...
552
553
554
555
556
557
558
559
560
561
  	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...
562
  	GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
ee2b805c8   Linus Walleij   ARM: 5678/1: SSP/...
563
  	GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
556f4aeb7   Linus Walleij   spi/pl022: fix up...
564
565
566
  	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...
567
  )
781c7b129   Linus Walleij   spi/pl022: add su...
568
569
570
571
572
573
574
  /* 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...
575
576
577
578
  #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...
579
  	GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) \
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
580
  )
556f4aeb7   Linus Walleij   spi/pl022: fix up...
581
582
583
584
585
586
587
588
589
  /* 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...
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  /*
   * 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...
604

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
605
  #define DEFAULT_SSP_REG_CPSR ( \
556f4aeb7   Linus Walleij   spi/pl022: fix up...
606
  	GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
607
608
609
610
611
612
  )
  
  #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...
613
614
615
616
  /**
   * load_ssp_default_config - Load default configuration for SSP
   * @pl022: SSP driver private data structure
   */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
617
618
  static void load_ssp_default_config(struct pl022 *pl022)
  {
781c7b129   Linus Walleij   spi/pl022: add su...
619
620
621
622
  	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...
623
624
625
626
627
628
  		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...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  	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));
  }
  
  /**
   * 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...
643
  	 * The FIFO depth is different between primecell variants.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
644
645
646
647
  	 * 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 ...
648
649
650
  	 * 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...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  	 */
  	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 ...
678
  		pl022->exp_fifo_level--;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
679
680
  	}
  	/*
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
681
  	 * Write as much as possible up to the RX FIFO size
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
682
  	 */
fc05475f8   Linus Walleij   ARM: 5893/1: SPI ...
683
  	while ((pl022->exp_fifo_level < pl022->vendor->fifodepth)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
  	       && (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 ...
700
  		pl022->exp_fifo_level++;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
701
702
703
704
  		/*
  		 * 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...
705
  		 * and then things are continuously clocked into the RX FIFO.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  		 */
  		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 ...
727
  			pl022->exp_fifo_level--;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
728
729
730
731
732
733
734
  		}
  	}
  	/*
  	 * When we exit here the TX FIFO should be full and the RX FIFO
  	 * should be empty
  	 */
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
  /**
   * 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...
758
759
760
761
762
763
764
765
766
  
  /*
   * 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...
767
  	dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
768
  		     pl022->sgt_tx.nents, DMA_TO_DEVICE);
b72988968   Linus Walleij   spi/pl022: map th...
769
  	dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
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
  		     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...
822
  	/* Update total bytes transferred */
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
823
824
  	msg->actual_length += pl022->cur_transfer->len;
  	if (pl022->cur_transfer->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
825
  		pl022_cs_control(pl022, SSP_CHIP_DESELECT);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
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
  
  	/* Move to next transfer */
  	msg->state = next_transfer(pl022);
  	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...
892
  		.direction = DMA_DEV_TO_MEM,
258aea76f   Viresh Kumar   dmaengine: Pass d...
893
  		.device_fc = false,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
894
895
896
  	};
  	struct dma_slave_config tx_conf = {
  		.dst_addr = SSP_DR(pl022->phybase),
a485df4b4   Vinod Koul   spi, serial: move...
897
  		.direction = DMA_MEM_TO_DEV,
258aea76f   Viresh Kumar   dmaengine: Pass d...
898
  		.device_fc = false,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
899
900
901
  	};
  	unsigned int pages;
  	int ret;
082086f2c   Linus Walleij   spi/pl022: pass t...
902
  	int rx_sglen, tx_sglen;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
903
904
905
906
  	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...
907
908
909
910
  
  	/* Check that the channels are available */
  	if (!rxchan || !txchan)
  		return -ENODEV;
083be3f05   Linus Walleij   spi/pl022: initia...
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
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
  	/*
  	 * 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...
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  	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...
986
  		tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
987
988
989
990
991
992
993
994
995
  		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...
996
997
  	dmaengine_slave_config(rxchan, &rx_conf);
  	dmaengine_slave_config(txchan, &tx_conf);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
998
999
  
  	/* Create sglists for the transfers */
b181565ee   Viresh Kumar   spi/spi-pl022: Do...
1000
  	pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1001
1002
  	dev_dbg(&pl022->adev->dev, "using %d pages for transfer
  ", pages);
538a18dc1   Viresh Kumar   spi/spi-pl022: Us...
1003
  	ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1004
1005
  	if (ret)
  		goto err_alloc_rx_sg;
538a18dc1   Viresh Kumar   spi/spi-pl022: Us...
1006
  	ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
  	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...
1017
  	rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1018
  			   pl022->sgt_rx.nents, DMA_FROM_DEVICE);
082086f2c   Linus Walleij   spi/pl022: pass t...
1019
  	if (!rx_sglen)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1020
  		goto err_rx_sgmap;
082086f2c   Linus Walleij   spi/pl022: pass t...
1021
  	tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1022
  			   pl022->sgt_tx.nents, DMA_TO_DEVICE);
082086f2c   Linus Walleij   spi/pl022: pass t...
1023
  	if (!tx_sglen)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1024
1025
1026
  		goto err_tx_sgmap;
  
  	/* Send both scatterlists */
16052827d   Alexandre Bounine   dmaengine/dma_sla...
1027
  	rxdesc = dmaengine_prep_slave_sg(rxchan,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1028
  				      pl022->sgt_rx.sgl,
082086f2c   Linus Walleij   spi/pl022: pass t...
1029
  				      rx_sglen,
a485df4b4   Vinod Koul   spi, serial: move...
1030
  				      DMA_DEV_TO_MEM,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1031
1032
1033
  				      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
  	if (!rxdesc)
  		goto err_rxdesc;
16052827d   Alexandre Bounine   dmaengine/dma_sla...
1034
  	txdesc = dmaengine_prep_slave_sg(txchan,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1035
  				      pl022->sgt_tx.sgl,
082086f2c   Linus Walleij   spi/pl022: pass t...
1036
  				      tx_sglen,
a485df4b4   Vinod Koul   spi, serial: move...
1037
  				      DMA_MEM_TO_DEV,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1038
1039
1040
1041
1042
1043
1044
1045
1046
  				      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...
1047
1048
1049
1050
  	dmaengine_submit(rxdesc);
  	dmaengine_submit(txdesc);
  	dma_async_issue_pending(rxchan);
  	dma_async_issue_pending(txchan);
ffbbdd213   Linus Walleij   spi: create a mes...
1051
  	pl022->dma_running = true;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1052
1053
  
  	return 0;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1054
  err_txdesc:
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1055
  	dmaengine_terminate_all(txchan);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1056
  err_rxdesc:
ecd442fd9   Linus Walleij   spi/pl022: use dm...
1057
  	dmaengine_terminate_all(rxchan);
b72988968   Linus Walleij   spi/pl022: map th...
1058
  	dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1059
1060
  		     pl022->sgt_tx.nents, DMA_TO_DEVICE);
  err_tx_sgmap:
b72988968   Linus Walleij   spi/pl022: map th...
1061
  	dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1062
1063
1064
1065
1066
1067
1068
1069
  		     pl022->sgt_tx.nents, DMA_FROM_DEVICE);
  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...
1070
  static int pl022_dma_probe(struct pl022 *pl022)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
  {
  	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...
1085
1086
  		dev_dbg(&pl022->adev->dev, "no RX DMA channel!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1087
1088
1089
1090
1091
1092
1093
  		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...
1094
1095
  		dev_dbg(&pl022->adev->dev, "no TX DMA channel!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1096
1097
1098
1099
1100
  		goto err_no_txchan;
  	}
  
  	pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	if (!pl022->dummypage) {
43c640157   Viresh Kumar   spi/amba-pl022: w...
1101
1102
  		dev_dbg(&pl022->adev->dev, "no DMA dummypage!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  		goto err_no_dummypage;
  	}
  
  	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...
1119
1120
1121
  	dev_err(&pl022->adev->dev,
  			"Failed to work in dma mode, work without dma!
  ");
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1122
1123
  	return -ENODEV;
  }
dc715452e   Arnd Bergmann   spi: pl022: use g...
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  static int pl022_dma_autoprobe(struct pl022 *pl022)
  {
  	struct device *dev = &pl022->adev->dev;
  
  	/* automatically configure DMA channels from platform, normally using DT */
  	pl022->dma_rx_channel = dma_request_slave_channel(dev, "rx");
  	if (!pl022->dma_rx_channel)
  		goto err_no_rxchan;
  
  	pl022->dma_tx_channel = dma_request_slave_channel(dev, "tx");
  	if (!pl022->dma_tx_channel)
  		goto err_no_txchan;
  
  	pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	if (!pl022->dummypage)
  		goto err_no_dummypage;
  
  	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:
  	return -ENODEV;
  }
  		
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1153
1154
1155
1156
  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...
1157
1158
  	dmaengine_terminate_all(rxchan);
  	dmaengine_terminate_all(txchan);
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1159
  	unmap_free_dma_scatter(pl022);
ffbbdd213   Linus Walleij   spi: create a mes...
1160
  	pl022->dma_running = false;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1161
1162
1163
1164
  }
  
  static void pl022_dma_remove(struct pl022 *pl022)
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1165
  	if (pl022->dma_running)
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  		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...
1179
1180
1181
1182
  static inline int pl022_dma_autoprobe(struct pl022 *pl022)
  {
  	return 0;
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1183
1184
1185
1186
1187
1188
1189
1190
1191
  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...
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
  /**
   * pl022_interrupt_handler - Interrupt handler for SSP controller
   *
   * 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;
  	u16 flag = 0;
  
  	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...
1222
1223
1224
1225
1226
  	/*
  	 * This handles the FIFO interrupts, the timeout
  	 * interrupts are flatly ignored, they cannot be
  	 * trusted.
  	 */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1227
1228
1229
1230
1231
  	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...
1232
1233
  		dev_err(&pl022->adev->dev, "FIFO overrun
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
  		if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
  			dev_err(&pl022->adev->dev,
  				"RXFIFO is full
  ");
  		if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
  			dev_err(&pl022->adev->dev,
  				"TXFIFO is full
  ");
  
  		/*
  		 * 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);
  
  	if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
  		flag = 1;
172289df4   Chris Blair   spi/pl022: only e...
1264
1265
1266
  		/* 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...
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
  		       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...
1286
  		/* Update total bytes transferred */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1287
1288
  		msg->actual_length += pl022->cur_transfer->len;
  		if (pl022->cur_transfer->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1289
  			pl022_cs_control(pl022, SSP_CHIP_DESELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
  		/* Move to next transfer */
  		msg->state = next_transfer(pl022);
  		tasklet_schedule(&pl022->pump_transfers);
  		return IRQ_HANDLED;
  	}
  
  	return IRQ_HANDLED;
  }
  
  /**
   * 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...
1332
1333
   * pump_transfers - Tasklet function which schedules next transfer
   * when running in interrupt or DMA transfer mode.
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
   * @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);
  		if (previous->delay_usecs)
  			/*
  			 * FIXME: This runs in interrupt context.
  			 * Is this really smart?
  			 */
  			udelay(previous->delay_usecs);
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
1373
  		/* Reselect chip select only if cs_change was requested */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1374
  		if (previous->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1375
  			pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
  	} 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...
1389

b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1390
1391
1392
1393
1394
1395
1396
  	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...
1397
1398
  		return;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1399

b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1400
  err_config_dma:
172289df4   Chris Blair   spi/pl022: only e...
1401
1402
  	/* enable all interrupts except RX */
  	writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1403
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1404
  static void do_interrupt_dma_transfer(struct pl022 *pl022)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1405
  {
172289df4   Chris Blair   spi/pl022: only e...
1406
1407
1408
1409
1410
  	/*
  	 * Default is to enable all interrupts except RX -
  	 * this will be enabled once TX is complete
  	 */
  	u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1411

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

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1416
1417
1418
1419
1420
1421
1422
  	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...
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
  	/* 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...
1436
1437
1438
  	/* 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...
1439
  	writew(irqflags, SSP_IMSC(pl022->virtbase));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1440
  }
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1441
  static void do_polling_transfer(struct pl022 *pl022)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1442
  {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1443
1444
1445
1446
  	struct spi_message *message = NULL;
  	struct spi_transfer *transfer = NULL;
  	struct spi_transfer *previous = NULL;
  	struct chip_data *chip;
a18c266f8   Magnus Templing   spi/pl022: timeou...
1447
  	unsigned long time, timeout;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  
  	chip = pl022->cur_chip;
  	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);
  			if (previous->delay_usecs)
  				udelay(previous->delay_usecs);
  			if (previous->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1466
  				pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1467
1468
1469
  		} else {
  			/* STATE_START */
  			message->state = STATE_RUNNING;
8b8d71916   Virupax Sadashivpetimath   spi/pl022: make t...
1470
  			if (!pl022->next_msg_cs_active)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1471
  				pl022_cs_control(pl022, SSP_CHIP_SELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
  		}
  
  		/* 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...
1484
1485
  		dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...
  ");
a18c266f8   Magnus Templing   spi/pl022: timeou...
1486
1487
1488
1489
  
  		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...
1490
  			readwriter(pl022);
a18c266f8   Magnus Templing   spi/pl022: timeou...
1491
1492
1493
1494
1495
1496
1497
  			if (time_after(time, timeout)) {
  				dev_warn(&pl022->adev->dev,
  				"%s: timeout!
  ", __func__);
  				message->state = STATE_ERROR;
  				goto out;
  			}
521999bd4   Linus Walleij   spi/pl022: use cp...
1498
  			cpu_relax();
a18c266f8   Magnus Templing   spi/pl022: timeou...
1499
  		}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1500

25985edce   Lucas De Marchi   Fix common misspe...
1501
  		/* Update total byte transferred */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1502
1503
  		message->actual_length += pl022->cur_transfer->len;
  		if (pl022->cur_transfer->cs_change)
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1504
  			pl022_cs_control(pl022, SSP_CHIP_DESELECT);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1505
1506
1507
  		/* Move to next transfer */
  		message->state = next_transfer(pl022);
  	}
a18c266f8   Magnus Templing   spi/pl022: timeou...
1508
  out:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1509
1510
1511
1512
1513
1514
1515
1516
1517
  	/* Handle end of message */
  	if (message->state == STATE_DONE)
  		message->status = 0;
  	else
  		message->status = -EIO;
  
  	giveback(pl022);
  	return;
  }
ffbbdd213   Linus Walleij   spi: create a mes...
1518
1519
  static int pl022_transfer_one_message(struct spi_master *master,
  				      struct spi_message *msg)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1520
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1521
  	struct pl022 *pl022 = spi_master_get_devdata(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1522
1523
  
  	/* Initial message state */
ffbbdd213   Linus Walleij   spi: create a mes...
1524
1525
1526
1527
1528
  	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...
1529
1530
  
  	/* Setup the SPI using the per chip configuration */
ffbbdd213   Linus Walleij   spi: create a mes...
1531
  	pl022->cur_chip = spi_get_ctldata(msg->spi);
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1532
  	pl022->cur_cs = pl022->chipselects[msg->spi->chip_select];
d4b6af2e0   Chris Blair   spi/pl022: move d...
1533

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1534
1535
1536
1537
1538
  	restore_state(pl022);
  	flush(pl022);
  
  	if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
  		do_polling_transfer(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1539
  	else
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
1540
  		do_interrupt_dma_transfer(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1541
1542
1543
  
  	return 0;
  }
ffbbdd213   Linus Walleij   spi: create a mes...
1544
  static int pl022_prepare_transfer_hardware(struct spi_master *master)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1545
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1546
  	struct pl022 *pl022 = spi_master_get_devdata(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1547

ffbbdd213   Linus Walleij   spi: create a mes...
1548
1549
1550
1551
1552
  	/*
  	 * Just make sure we have all we need to run the transfer by syncing
  	 * with the runtime PM framework.
  	 */
  	pm_runtime_get_sync(&pl022->adev->dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1553
1554
  	return 0;
  }
ffbbdd213   Linus Walleij   spi: create a mes...
1555
  static int pl022_unprepare_transfer_hardware(struct spi_master *master)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1556
  {
ffbbdd213   Linus Walleij   spi: create a mes...
1557
  	struct pl022 *pl022 = spi_master_get_devdata(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1558

ffbbdd213   Linus Walleij   spi: create a mes...
1559
1560
1561
  	/* 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...
1562

ffbbdd213   Linus Walleij   spi: create a mes...
1563
1564
1565
1566
1567
  	if (pl022->master_info->autosuspend_delay > 0) {
  		pm_runtime_mark_last_busy(&pl022->adev->dev);
  		pm_runtime_put_autosuspend(&pl022->adev->dev);
  	} else {
  		pm_runtime_put(&pl022->adev->dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1568
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1569
1570
1571
1572
  	return 0;
  }
  
  static int verify_controller_parameters(struct pl022 *pl022,
f9d629c73   Linus Walleij   spi/pl022: fix du...
1573
  				struct pl022_config_chip const *chip_info)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1574
  {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1575
1576
  	if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
  	    || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1577
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1578
1579
1580
1581
1582
1583
  			"interface is configured incorrectly
  ");
  		return -EINVAL;
  	}
  	if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
  	    (!pl022->vendor->unidir)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1584
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1585
1586
1587
1588
1589
1590
1591
  			"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...
1592
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1593
1594
1595
1596
  			"hierarchy is configured incorrectly
  ");
  		return -EINVAL;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1597
1598
1599
  	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...
1600
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1601
1602
1603
1604
  			"Communication mode is configured incorrectly
  ");
  		return -EINVAL;
  	}
78b2b911b   Linus Walleij   spi/pl022: streng...
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
  	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...
1628
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1629
1630
1631
  			"RX FIFO Trigger Level is configured incorrectly
  ");
  		return -EINVAL;
78b2b911b   Linus Walleij   spi/pl022: streng...
1632
  		break;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1633
  	}
78b2b911b   Linus Walleij   spi/pl022: streng...
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
  	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...
1657
  		dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1658
1659
1660
  			"TX FIFO Trigger Level is configured incorrectly
  ");
  		return -EINVAL;
78b2b911b   Linus Walleij   spi/pl022: streng...
1661
  		break;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1662
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1663
1664
1665
  	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...
1666
  			dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1667
1668
1669
1670
1671
1672
  				"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...
1673
  			dev_err(&pl022->adev->dev,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1674
1675
1676
1677
  				"Wait State is configured incorrectly
  ");
  			return -EINVAL;
  		}
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1678
1679
1680
1681
1682
  		/* 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...
1683
  				SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1684
  				dev_err(&pl022->adev->dev,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1685
1686
1687
  					"Microwire duplex mode is configured incorrectly
  ");
  				return -EINVAL;
4a4fd4715   Julia Lawall   spi/amba-pl022: F...
1688
  			}
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1689
1690
  		} else {
  			if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
5a1c98be1   Linus Walleij   spi/pl022: get ri...
1691
  				dev_err(&pl022->adev->dev,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1692
1693
1694
1695
  					"Microwire half duplex mode requested,"
  					" but this is only available in the"
  					" ST version of PL022
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1696
1697
1698
  			return -EINVAL;
  		}
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1699
1700
  	return 0;
  }
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1701
1702
1703
1704
1705
1706
1707
  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...
1708
1709
  {
  	/* Lets calculate the frequency parameters */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1710
1711
1712
  	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...
1713
1714
1715
  
  	rate = clk_get_rate(pl022->clk);
  	/* cpsdvscr = 2 & scr 0 */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1716
  	max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1717
  	/* cpsdvsr = 254 & scr = 255 */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1718
  	min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
ea505bc99   Viresh Kumar   spi/pl022: Allow ...
1719
1720
1721
1722
1723
1724
1725
  	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...
1726
  		dev_err(&pl022->adev->dev,
ea505bc99   Viresh Kumar   spi/pl022: Allow ...
1727
1728
1729
  			"Requested frequency: %d Hz is less than minimum possible %d Hz
  ",
  			freq, min_tclk);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1730
1731
  		return -EINVAL;
  	}
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1732
1733
1734
1735
1736
1737
1738
1739
  
  	/*
  	 * 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...
1740
1741
  			if (tmp > freq) {
  				/* we need lower freq */
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1742
  				scr++;
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1743
1744
  				continue;
  			}
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1745
  			/*
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1746
1747
  			 * If found exact value, mark found and break.
  			 * If found more closer value, update and break.
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1748
  			 */
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1749
  			if (tmp > best_freq) {
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1750
1751
1752
1753
1754
  				best_freq = tmp;
  				best_cpsdvsr = cpsdvsr;
  				best_scr = scr;
  
  				if (tmp == freq)
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1755
  					found = 1;
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1756
  			}
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1757
1758
1759
1760
1761
  			/*
  			 * increased scr will give lower rates, which are not
  			 * required
  			 */
  			break;
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1762
1763
1764
1765
  		}
  		cpsdvsr += 2;
  		scr = SCR_MIN;
  	}
5eb806a3a   Viresh Kumar   spi/pl022: Fix ca...
1766
1767
1768
  	WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate 
  ",
  			freq);
0379b2a33   Viresh Kumar   spi/spi-pl022: ca...
1769
1770
1771
1772
1773
1774
1775
1776
1777
  	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...
1778
1779
  	return 0;
  }
f9d629c73   Linus Walleij   spi/pl022: fix du...
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
  /*
   * 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...
1796
  /**
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
   * 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...
1808
1809
  static int pl022_setup(struct spi_device *spi)
  {
f9d629c73   Linus Walleij   spi/pl022: fix du...
1810
  	struct pl022_config_chip const *chip_info;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
1811
  	struct pl022_config_chip chip_info_dt;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1812
  	struct chip_data *chip;
c4a478430   Jonas Aaberg   spi/pl022: fix bu...
1813
  	struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1814
1815
  	int status = 0;
  	struct pl022 *pl022 = spi_master_get_devdata(spi->master);
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1816
1817
  	unsigned int bits = spi->bits_per_word;
  	u32 tmp;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
1818
  	struct device_node *np = spi->dev.of_node;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
  
  	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);
  		if (!chip) {
  			dev_err(&spi->dev,
  				"cannot allocate controller state
  ");
  			return -ENOMEM;
  		}
  		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...
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
  		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...
1870
  	} else
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1871
1872
1873
  		dev_dbg(&spi->dev,
  			"using user supplied controller_data settings
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1874
1875
1876
1877
1878
1879
1880
1881
1882
  
  	/*
  	 * 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...
1883
  						  &clk_freq);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1884
1885
1886
  		if (status < 0)
  			goto err_config_params;
  	} else {
f9d629c73   Linus Walleij   spi/pl022: fix du...
1887
1888
1889
1890
  		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...
1891
  	}
f9d629c73   Linus Walleij   spi/pl022: fix du...
1892
1893
  	if ((clk_freq.cpsdvsr < CPSDVR_MIN)
  	    || (clk_freq.cpsdvsr > CPSDVR_MAX)) {
e3f88ae99   Virupax Sadashivpetimath   spi-pl022: Add mi...
1894
  		status = -EINVAL;
f9d629c73   Linus Walleij   spi/pl022: fix du...
1895
1896
1897
1898
1899
  		dev_err(&spi->dev,
  			"cpsdvsr is configured incorrectly
  ");
  		goto err_config_params;
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1900
1901
1902
1903
1904
  	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...
1905

083be3f05   Linus Walleij   spi/pl022: initia...
1906
1907
  	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...
1908
1909
  	/* Now set controller state based on controller data */
  	chip->xfer_type = chip_info->com_mode;
f9d629c73   Linus Walleij   spi/pl022: fix du...
1910
1911
  	if (!chip_info->cs_control) {
  		chip->cs_control = null_cs_control;
f6f46de10   Roland Stigge   spi/pl022: Add ch...
1912
1913
1914
1915
  		if (!gpio_is_valid(pl022->chipselects[spi->chip_select]))
  			dev_warn(&spi->dev,
  				 "invalid chip select
  ");
f9d629c73   Linus Walleij   spi/pl022: fix du...
1916
1917
  	} else
  		chip->cs_control = chip_info->cs_control;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1918

eb798c641   Vinit Shenoy   spi/pl022: Fix ra...
1919
1920
  	/* Check bits per word with vendor specific range */
  	if ((bits <= 3) || (bits > pl022->vendor->max_bpw)) {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1921
  		status = -ENOTSUPP;
eb798c641   Vinit Shenoy   spi/pl022: Fix ra...
1922
1923
1924
1925
1926
  		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...
1927
1928
1929
1930
  		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...
1931
1932
1933
  		chip->n_bytes = 1;
  		chip->read = READING_U8;
  		chip->write = WRITING_U8;
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1934
  	} else if (bits <= 16) {
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1935
1936
1937
1938
1939
1940
  		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...
1941
1942
1943
1944
1945
  		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...
1946
1947
1948
1949
1950
1951
1952
1953
1954
  	}
  
  	/* 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...
1955
  		chip->enable_dma = true;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1956
1957
  		dev_dbg(&spi->dev, "DMA mode set in controller state
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1958
1959
1960
1961
1962
  		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...
1963
  		chip->enable_dma = false;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1964
1965
1966
1967
1968
1969
1970
  		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...
1971
  	chip->cpsr = clk_freq.cpsdvsr;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
1972

556f4aeb7   Linus Walleij   spi/pl022: fix up...
1973
1974
  	/* Special setup for the ST micro extended control registers */
  	if (pl022->vendor->extended_cr) {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1975
  		u32 etx;
781c7b129   Linus Walleij   spi/pl022: add su...
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
  		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...
1991
  		SSP_WRITE_BITS(chip->cr0, bits - 1,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
1992
  			       SSP_CR0_MASK_DSS_ST, 0);
bde435a9c   Kevin Wells   spi/pl022: Add sp...
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
  
  		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...
2003
2004
2005
2006
2007
  		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...
2008
  		SSP_WRITE_BITS(chip->cr0, bits - 1,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2009
2010
2011
2012
  			       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...
2013

556f4aeb7   Linus Walleij   spi/pl022: fix up...
2014
  	/* Stuff that is common for all versions */
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
  	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...
2026
  	SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8);
781c7b129   Linus Walleij   spi/pl022: add su...
2027
  	/* Loopback is available on all versions except PL023 */
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2028
  	if (pl022->vendor->loopback) {
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2029
2030
2031
2032
2033
2034
  		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...
2035
2036
  	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...
2037
2038
  	SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD,
  		3);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2039
2040
2041
2042
2043
  
  	/* Save controller_state */
  	spi_set_ctldata(spi, chip);
  	return status;
   err_config_params:
bde435a9c   Kevin Wells   spi/pl022: Add sp...
2044
  	spi_set_ctldata(spi, NULL);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
  	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...
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
  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;
  	u32 tmp;
  
  	if (!np) {
  		dev_err(dev, "no dt node defined
  ");
  		return NULL;
  	}
  
  	pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
  	if (!pd) {
  		dev_err(dev, "cannot allocate platform data memory
  ");
  		return NULL;
  	}
  
  	pd->bus_id = -1;
  	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...
2092
  static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2093
2094
2095
2096
2097
  {
  	struct device *dev = &adev->dev;
  	struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
  	struct spi_master *master;
  	struct pl022 *pl022 = NULL;	/*Data for this driver */
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2098
2099
  	struct device_node *np = adev->dev.of_node;
  	int status = 0, i, num_cs;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2100
2101
2102
2103
  
  	dev_info(&adev->dev,
  		 "ARM PL022 driver, device ID: 0x%08x
  ", adev->periphid);
39a6ac11d   Roland Stigge   spi/pl022: Device...
2104
2105
2106
2107
2108
2109
  	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...
2110
  		return -ENODEV;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2111
  	}
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2112
2113
  	if (platform_info->num_chipselect) {
  		num_cs = platform_info->num_chipselect;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2114
  	} else {
39a6ac11d   Roland Stigge   spi/pl022: Device...
2115
2116
  		dev_err(dev, "probe: no chip select defined
  ");
aeef9915b   Linus Walleij   spi/pl022: use mo...
2117
  		return -ENODEV;
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2118
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2119
  	/* Allocate master with space for data */
b4b848269   Roland Stigge   spi/pl022: Fix ch...
2120
  	master = spi_alloc_master(dev, sizeof(struct pl022));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2121
2122
2123
  	if (master == NULL) {
  		dev_err(&adev->dev, "probe - cannot alloc SPI master
  ");
aeef9915b   Linus Walleij   spi/pl022: use mo...
2124
  		return -ENOMEM;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2125
2126
2127
2128
2129
2130
2131
  	}
  
  	pl022 = spi_master_get_devdata(master);
  	pl022->master = master;
  	pl022->master_info = platform_info;
  	pl022->adev = adev;
  	pl022->vendor = id->data;
b4b848269   Roland Stigge   spi/pl022: Fix ch...
2132
2133
  	pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
  					  GFP_KERNEL);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2134

4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
  	pl022->pinctrl = devm_pinctrl_get(dev);
  	if (IS_ERR(pl022->pinctrl)) {
  		status = PTR_ERR(pl022->pinctrl);
  		goto err_no_pinctrl;
  	}
  
  	pl022->pins_default = pinctrl_lookup_state(pl022->pinctrl,
  						 PINCTRL_STATE_DEFAULT);
  	/* enable pins to be muxed in and configured */
  	if (!IS_ERR(pl022->pins_default)) {
  		status = pinctrl_select_state(pl022->pinctrl,
  				pl022->pins_default);
  		if (status)
  			dev_err(dev, "could not set default pins
  ");
  	} else
  		dev_err(dev, "could not get default pinstate
  ");
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2153
2154
2155
2156
2157
  	pl022->pins_idle = pinctrl_lookup_state(pl022->pinctrl,
  					      PINCTRL_STATE_IDLE);
  	if (IS_ERR(pl022->pins_idle))
  		dev_dbg(dev, "could not get idle pinstate
  ");
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
2158
2159
2160
2161
2162
  	pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl,
  					       PINCTRL_STATE_SLEEP);
  	if (IS_ERR(pl022->pins_sleep))
  		dev_dbg(dev, "could not get sleep pinstate
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
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;
ffbbdd213   Linus Walleij   spi: create a mes...
2171
2172
2173
2174
  	master->prepare_transfer_hardware = pl022_prepare_transfer_hardware;
  	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];
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
  	} 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...
2192
  				if (devm_gpio_request(dev, cs_gpio, "ssp-pl022"))
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
  					dev_err(&adev->dev,
  						"could not request %d gpio
  ",
  						cs_gpio);
  				else if (gpio_direction_output(cs_gpio, 1))
  					dev_err(&adev->dev,
  						"could set gpio %d as output
  ",
  						cs_gpio);
  			}
  		}
  	}
f6f46de10   Roland Stigge   spi/pl022: Add ch...
2205

bde435a9c   Kevin Wells   spi/pl022: Add sp...
2206
2207
2208
2209
2210
2211
2212
  	/*
  	 * 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...
2213
2214
2215
2216
2217
2218
  	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...
2219
  	pl022->phybase = adev->res.start;
aeef9915b   Linus Walleij   spi/pl022: use mo...
2220
2221
  	pl022->virtbase = devm_ioremap(dev, adev->res.start,
  				       resource_size(&adev->res));
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2222
2223
2224
2225
2226
2227
2228
  	if (pl022->virtbase == NULL) {
  		status = -ENOMEM;
  		goto err_no_ioremap;
  	}
  	printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p
  ",
  	       adev->res.start, pl022->virtbase);
aeef9915b   Linus Walleij   spi/pl022: use mo...
2229
  	pl022->clk = devm_clk_get(&adev->dev, NULL);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2230
2231
2232
2233
2234
2235
  	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...
2236
2237
2238
2239
2240
2241
2242
  
  	status = clk_prepare(pl022->clk);
  	if (status) {
  		dev_err(&adev->dev, "could not prepare SSP/SPI bus clock
  ");
  		goto  err_clk_prep;
  	}
71e63e748   Ulf Hansson   ARM: 7149/1: spi/...
2243
2244
2245
2246
2247
2248
  	status = clk_enable(pl022->clk);
  	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...
2249
2250
2251
  	/* Initialize transfer pump */
  	tasklet_init(&pl022->pump_transfers, pump_transfers,
  		     (unsigned long)pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2252
  	/* Disable SSP */
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2253
2254
2255
  	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...
2256

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

dc715452e   Arnd Bergmann   spi: pl022: use g...
2265
2266
2267
2268
2269
2270
2271
  	/* Get DMA channels, try autoconfiguration first */
  	status = pl022_dma_autoprobe(pl022);
  
  	/* 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...
2272
2273
  		status = pl022_dma_probe(pl022);
  		if (status != 0)
43c640157   Viresh Kumar   spi/amba-pl022: w...
2274
  			platform_info->enable_dma = 0;
b1b6b9aa6   Linus Walleij   spi/pl022: add Pr...
2275
  	}
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2276
2277
2278
2279
2280
2281
2282
2283
2284
  	/* Register with the SPI framework */
  	amba_set_drvdata(adev, pl022);
  	status = spi_register_master(master);
  	if (status != 0) {
  		dev_err(&adev->dev,
  			"probe - problem registering spi master
  ");
  		goto err_spi_register;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
2285
2286
  	dev_dbg(dev, "probe succeeded
  ");
92b97f0aa   Russell King   PM: add runtime P...
2287
2288
  
  	/* let runtime pm put suspend */
53e4acea0   Chris Blair   spi/pl022: add su...
2289
2290
2291
2292
2293
2294
2295
2296
  	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...
2297
  	}
0df349945   Ulf Hansson   spi/pl022: Minor ...
2298
  	pm_runtime_put(dev);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2299
2300
2301
  	return 0;
  
   err_spi_register:
3e3ea7162   Viresh Kumar   spi/spi-pl022: Ca...
2302
2303
  	if (platform_info->enable_dma)
  		pl022_dma_remove(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2304
   err_no_irq:
71e63e748   Ulf Hansson   ARM: 7149/1: spi/...
2305
2306
  	clk_disable(pl022->clk);
   err_no_clk_en:
7ff6bcf04   Russell King   clk: spi-pl022: c...
2307
2308
  	clk_unprepare(pl022->clk);
   err_clk_prep:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2309
   err_no_clk:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2310
2311
2312
   err_no_ioremap:
  	amba_release_regions(adev);
   err_no_ioregion:
6d3952a7d   Roland Stigge   spi/pl022: Add de...
2313
   err_no_gpio:
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
2314
   err_no_pinctrl:
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2315
  	spi_master_put(master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2316
2317
  	return status;
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
2318
  static int
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2319
2320
2321
  pl022_remove(struct amba_device *adev)
  {
  	struct pl022 *pl022 = amba_get_drvdata(adev);
50658b660   Linus Walleij   spi/pl022: remove...
2322

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2323
2324
  	if (!pl022)
  		return 0;
92b97f0aa   Russell King   PM: add runtime P...
2325
2326
2327
2328
2329
  	/*
  	 * 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...
2330
  	load_ssp_default_config(pl022);
3e3ea7162   Viresh Kumar   spi/spi-pl022: Ca...
2331
2332
  	if (pl022->master_info->enable_dma)
  		pl022_dma_remove(pl022);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2333
  	clk_disable(pl022->clk);
7ff6bcf04   Russell King   clk: spi-pl022: c...
2334
  	clk_unprepare(pl022->clk);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2335
2336
2337
  	amba_release_regions(adev);
  	tasklet_disable(&pl022->pump_transfers);
  	spi_unregister_master(pl022->master);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2338
  	amba_set_drvdata(adev, NULL);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2339
2340
  	return 0;
  }
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2341
2342
2343
2344
2345
2346
  #if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
  /*
   * These two functions are used from both suspend/resume and
   * the runtime counterparts to handle external resources like
   * clocks, pins and regulators when going to sleep.
   */
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2347
  static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2348
2349
  {
  	int ret;
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2350
  	struct pinctrl_state *pins_state;
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2351
2352
  
  	clk_disable(pl022->clk);
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2353
  	pins_state = runtime ? pl022->pins_idle : pl022->pins_sleep;
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2354
  	/* Optionally let pins go into sleep states */
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2355
2356
  	if (!IS_ERR(pins_state)) {
  		ret = pinctrl_select_state(pl022->pinctrl, pins_state);
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2357
  		if (ret)
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2358
2359
2360
  			dev_err(&pl022->adev->dev, "could not set %s pins
  ",
  				runtime ? "idle" : "sleep");
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2361
2362
  	}
  }
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2363
  static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2364
2365
2366
2367
  {
  	int ret;
  
  	/* Optionaly enable pins to be muxed in and configured */
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2368
  	/* First go to the default state */
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2369
  	if (!IS_ERR(pl022->pins_default)) {
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2370
  		ret = pinctrl_select_state(pl022->pinctrl, pl022->pins_default);
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2371
2372
2373
2374
2375
  		if (ret)
  			dev_err(&pl022->adev->dev,
  				"could not set default pins
  ");
  	}
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
  	if (!runtime) {
  		/* Then let's idle the pins until the next transfer happens */
  		if (!IS_ERR(pl022->pins_idle)) {
  			ret = pinctrl_select_state(pl022->pinctrl,
  					pl022->pins_idle);
  		if (ret)
  			dev_err(&pl022->adev->dev,
  				"could not set idle pins
  ");
  		}
  	}
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2387
2388
2389
  	clk_enable(pl022->clk);
  }
  #endif
92b97f0aa   Russell King   PM: add runtime P...
2390
  #ifdef CONFIG_SUSPEND
6cfa6279e   Peter Hüwe   ARM: 7079/1: spi:...
2391
  static int pl022_suspend(struct device *dev)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2392
  {
92b97f0aa   Russell King   PM: add runtime P...
2393
  	struct pl022 *pl022 = dev_get_drvdata(dev);
ffbbdd213   Linus Walleij   spi: create a mes...
2394
  	int ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2395

ffbbdd213   Linus Walleij   spi: create a mes...
2396
2397
2398
2399
2400
  	ret = spi_master_suspend(pl022->master);
  	if (ret) {
  		dev_warn(dev, "cannot suspend master
  ");
  		return ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2401
  	}
4964a26df   Ulf Hansson   spi/pl022: Activa...
2402
2403
  
  	pm_runtime_get_sync(dev);
d8f18420c   Patrice Chotard   spi/pl022: add ID...
2404
  	pl022_suspend_resources(pl022, false);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2405

6cfa6279e   Peter Hüwe   ARM: 7079/1: spi:...
2406
2407
  	dev_dbg(dev, "suspended
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2408
2409
  	return 0;
  }
92b97f0aa   Russell King   PM: add runtime P...
2410
  static int pl022_resume(struct device *dev)
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2411
  {
92b97f0aa   Russell King   PM: add runtime P...
2412
  	struct pl022 *pl022 = dev_get_drvdata(dev);
ffbbdd213   Linus Walleij   spi: create a mes...
2413
  	int ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2414

d8f18420c   Patrice Chotard   spi/pl022: add ID...
2415
  	pl022_resume_resources(pl022, false);
4964a26df   Ulf Hansson   spi/pl022: Activa...
2416
  	pm_runtime_put(dev);
ada7aec7e   Linus Walleij   spi/pl022: get/pu...
2417

b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2418
  	/* Start the queue running */
ffbbdd213   Linus Walleij   spi: create a mes...
2419
2420
2421
2422
  	ret = spi_master_resume(pl022->master);
  	if (ret)
  		dev_err(dev, "problem starting queue (%d)
  ", ret);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2423
  	else
92b97f0aa   Russell King   PM: add runtime P...
2424
2425
  		dev_dbg(dev, "resumed
  ");
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2426

ffbbdd213   Linus Walleij   spi: create a mes...
2427
  	return ret;
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2428
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2429
  #endif	/* CONFIG_PM */
92b97f0aa   Russell King   PM: add runtime P...
2430
2431
2432
2433
  #ifdef CONFIG_PM_RUNTIME
  static int pl022_runtime_suspend(struct device *dev)
  {
  	struct pl022 *pl022 = dev_get_drvdata(dev);
4f5e1b370   Patrice Chotard   spi/pl022: adopt ...
2434

d8f18420c   Patrice Chotard   spi/pl022: add ID...
2435
  	pl022_suspend_resources(pl022, true);
92b97f0aa   Russell King   PM: add runtime P...
2436
2437
2438
2439
2440
2441
  	return 0;
  }
  
  static int pl022_runtime_resume(struct device *dev)
  {
  	struct pl022 *pl022 = dev_get_drvdata(dev);
92b97f0aa   Russell King   PM: add runtime P...
2442

d8f18420c   Patrice Chotard   spi/pl022: add ID...
2443
  	pl022_resume_resources(pl022, true);
92b97f0aa   Russell King   PM: add runtime P...
2444
2445
2446
2447
2448
2449
2450
2451
  	return 0;
  }
  #endif
  
  static const struct dev_pm_ops pl022_dev_pm_ops = {
  	SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
  	SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2452
2453
2454
2455
  static struct vendor_data vendor_arm = {
  	.fifodepth = 8,
  	.max_bpw = 16,
  	.unidir = false,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2456
  	.extended_cr = false,
781c7b129   Linus Walleij   spi/pl022: add su...
2457
  	.pl023 = false,
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2458
  	.loopback = true,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2459
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2460
2461
2462
2463
  static struct vendor_data vendor_st = {
  	.fifodepth = 32,
  	.max_bpw = 32,
  	.unidir = false,
556f4aeb7   Linus Walleij   spi/pl022: fix up...
2464
  	.extended_cr = true,
781c7b129   Linus Walleij   spi/pl022: add su...
2465
  	.pl023 = false,
06fb01fd1   Philippe Langlais   spi/pl022: Add lo...
2466
  	.loopback = true,
781c7b129   Linus Walleij   spi/pl022: add su...
2467
2468
2469
2470
2471
2472
2473
2474
  };
  
  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...
2475
2476
  	.loopback = false,
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
  static struct amba_id pl022_ids[] = {
  	{
  		/*
  		 * 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...
2492
  		.id	= 0x01080022,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2493
2494
2495
  		.mask	= 0xffffffff,
  		.data	= &vendor_st,
  	},
781c7b129   Linus Walleij   spi/pl022: add su...
2496
2497
2498
2499
2500
2501
2502
2503
  	{
  		/*
  		 * 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...
2504
2505
2506
  		.id	= 0x00080023,
  		.mask	= 0xffffffff,
  		.data	= &vendor_st_pl023,
781c7b129   Linus Walleij   spi/pl022: add su...
2507
  	},
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2508
2509
  	{ 0, 0 },
  };
7eeac71b9   Dave Martin   spi: pl022: Enabl...
2510
  MODULE_DEVICE_TABLE(amba, pl022_ids);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2511
2512
2513
  static struct amba_driver pl022_driver = {
  	.drv = {
  		.name	= "ssp-pl022",
92b97f0aa   Russell King   PM: add runtime P...
2514
  		.pm	= &pl022_dev_pm_ops,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2515
2516
2517
  	},
  	.id_table	= pl022_ids,
  	.probe		= pl022_probe,
fd4a319bc   Grant Likely   spi: Remove HOTPL...
2518
  	.remove		= pl022_remove,
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2519
  };
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2520
2521
2522
2523
  static int __init pl022_init(void)
  {
  	return amba_driver_register(&pl022_driver);
  }
25c8e03bd   Linus Walleij   spi/pl022: move p...
2524
  subsys_initcall(pl022_init);
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2525
2526
2527
2528
2529
  
  static void __exit pl022_exit(void)
  {
  	amba_driver_unregister(&pl022_driver);
  }
b43d65f7e   Linus Walleij   [ARM] 5546/1: ARM...
2530
2531
2532
2533
2534
  module_exit(pl022_exit);
  
  MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
  MODULE_DESCRIPTION("PL022 SSP Controller Driver");
  MODULE_LICENSE("GPL");