1
1
/* linux/drivers/spi/spi_s3c24xx.c
2
2
*
3
3
* Copyright (c) 2006 Ben Dooks
4
- * Copyright (c) 2006 Simtec Electronics
4
+ * Copyright 2006-2009 Simtec Electronics
5
5
* Ben Dooks <ben@simtec.co.uk>
6
6
*
7
7
* This program is free software; you can redistribute it and/or modify
28
28
#include <plat/regs-spi.h>
29
29
#include <mach/spi.h>
30
30
31
+ #include <plat/fiq.h>
32
+ #include <asm/fiq.h>
33
+
34
+ #include "spi_s3c24xx_fiq.h"
35
+
31
36
/**
32
37
* s3c24xx_spi_devstate - per device data
33
38
* @hz: Last frequency calculated for @sppre field.
@@ -42,6 +47,13 @@ struct s3c24xx_spi_devstate {
42
47
u8 sppre ;
43
48
};
44
49
50
+ enum spi_fiq_mode {
51
+ FIQ_MODE_NONE = 0 ,
52
+ FIQ_MODE_TX = 1 ,
53
+ FIQ_MODE_RX = 2 ,
54
+ FIQ_MODE_TXRX = 3 ,
55
+ };
56
+
45
57
struct s3c24xx_spi {
46
58
/* bitbang has to be first */
47
59
struct spi_bitbang bitbang ;
@@ -52,6 +64,11 @@ struct s3c24xx_spi {
52
64
int len ;
53
65
int count ;
54
66
67
+ struct fiq_handler fiq_handler ;
68
+ enum spi_fiq_mode fiq_mode ;
69
+ unsigned char fiq_inuse ;
70
+ unsigned char fiq_claimed ;
71
+
55
72
void (* set_cs )(struct s3c2410_spi_info * spi ,
56
73
int cs , int pol );
57
74
@@ -67,6 +84,7 @@ struct s3c24xx_spi {
67
84
struct s3c2410_spi_info * pdata ;
68
85
};
69
86
87
+
70
88
#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
71
89
#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
72
90
@@ -127,7 +145,7 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
127
145
}
128
146
129
147
if (spi -> mode != cs -> mode ) {
130
- u8 spcon = SPCON_DEFAULT ;
148
+ u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK ;
131
149
132
150
if (spi -> mode & SPI_CPHA )
133
151
spcon |= S3C2410_SPCON_CPHA_FMTB ;
@@ -214,25 +232,211 @@ static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
214
232
return hw -> tx ? hw -> tx [count ] : 0 ;
215
233
}
216
234
235
+ #ifdef CONFIG_SPI_S3C24XX_FIQ
236
+ /* Support for FIQ based pseudo-DMA to improve the transfer speed.
237
+ *
238
+ * This code uses the assembly helper in spi_s3c24xx_spi.S which is
239
+ * used by the FIQ core to move data between main memory and the peripheral
240
+ * block. Since this is code running on the processor, there is no problem
241
+ * with cache coherency of the buffers, so we can use any buffer we like.
242
+ */
243
+
244
+ /**
245
+ * struct spi_fiq_code - FIQ code and header
246
+ * @length: The length of the code fragment, excluding this header.
247
+ * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
248
+ * @data: The code itself to install as a FIQ handler.
249
+ */
250
+ struct spi_fiq_code {
251
+ u32 length ;
252
+ u32 ack_offset ;
253
+ u8 data [0 ];
254
+ };
255
+
256
+ extern struct spi_fiq_code s3c24xx_spi_fiq_txrx ;
257
+ extern struct spi_fiq_code s3c24xx_spi_fiq_tx ;
258
+ extern struct spi_fiq_code s3c24xx_spi_fiq_rx ;
259
+
260
+ /**
261
+ * ack_bit - turn IRQ into IRQ acknowledgement bit
262
+ * @irq: The interrupt number
263
+ *
264
+ * Returns the bit to write to the interrupt acknowledge register.
265
+ */
266
+ static inline u32 ack_bit (unsigned int irq )
267
+ {
268
+ return 1 << (irq - IRQ_EINT0 );
269
+ }
270
+
271
+ /**
272
+ * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
273
+ * @hw: The hardware state.
274
+ *
275
+ * Claim the FIQ handler (only one can be active at any one time) and
276
+ * then setup the correct transfer code for this transfer.
277
+ *
278
+ * This call updates all the necessary state information if sucessful,
279
+ * so the caller does not need to do anything more than start the transfer
280
+ * as normal, since the IRQ will have been re-routed to the FIQ handler.
281
+ */
282
+ void s3c24xx_spi_tryfiq (struct s3c24xx_spi * hw )
283
+ {
284
+ struct pt_regs regs ;
285
+ enum spi_fiq_mode mode ;
286
+ struct spi_fiq_code * code ;
287
+ int ret ;
288
+
289
+ if (!hw -> fiq_claimed ) {
290
+ /* try and claim fiq if we haven't got it, and if not
291
+ * then return and simply use another transfer method */
292
+
293
+ ret = claim_fiq (& hw -> fiq_handler );
294
+ if (ret )
295
+ return ;
296
+ }
297
+
298
+ if (hw -> tx && !hw -> rx )
299
+ mode = FIQ_MODE_TX ;
300
+ else if (hw -> rx && !hw -> tx )
301
+ mode = FIQ_MODE_RX ;
302
+ else
303
+ mode = FIQ_MODE_TXRX ;
304
+
305
+ regs .uregs [fiq_rspi ] = (long )hw -> regs ;
306
+ regs .uregs [fiq_rrx ] = (long )hw -> rx ;
307
+ regs .uregs [fiq_rtx ] = (long )hw -> tx + 1 ;
308
+ regs .uregs [fiq_rcount ] = hw -> len - 1 ;
309
+ regs .uregs [fiq_rirq ] = (long )S3C24XX_VA_IRQ ;
310
+
311
+ set_fiq_regs (& regs );
312
+
313
+ if (hw -> fiq_mode != mode ) {
314
+ u32 * ack_ptr ;
315
+
316
+ hw -> fiq_mode = mode ;
317
+
318
+ switch (mode ) {
319
+ case FIQ_MODE_TX :
320
+ code = & s3c24xx_spi_fiq_tx ;
321
+ break ;
322
+ case FIQ_MODE_RX :
323
+ code = & s3c24xx_spi_fiq_rx ;
324
+ break ;
325
+ case FIQ_MODE_TXRX :
326
+ code = & s3c24xx_spi_fiq_txrx ;
327
+ break ;
328
+ default :
329
+ code = NULL ;
330
+ }
331
+
332
+ BUG_ON (!code );
333
+
334
+ ack_ptr = (u32 * )& code -> data [code -> ack_offset ];
335
+ * ack_ptr = ack_bit (hw -> irq );
336
+
337
+ set_fiq_handler (& code -> data , code -> length );
338
+ }
339
+
340
+ s3c24xx_set_fiq (hw -> irq , true);
341
+
342
+ hw -> fiq_mode = mode ;
343
+ hw -> fiq_inuse = 1 ;
344
+ }
345
+
346
+ /**
347
+ * s3c24xx_spi_fiqop - FIQ core code callback
348
+ * @pw: Data registered with the handler
349
+ * @release: Whether this is a release or a return.
350
+ *
351
+ * Called by the FIQ code when another module wants to use the FIQ, so
352
+ * return whether we are currently using this or not and then update our
353
+ * internal state.
354
+ */
355
+ static int s3c24xx_spi_fiqop (void * pw , int release )
356
+ {
357
+ struct s3c24xx_spi * hw = pw ;
358
+ int ret = 0 ;
359
+
360
+ if (release ) {
361
+ if (hw -> fiq_inuse )
362
+ ret = - EBUSY ;
363
+
364
+ /* note, we do not need to unroute the FIQ, as the FIQ
365
+ * vector code de-routes it to signal the end of transfer */
366
+
367
+ hw -> fiq_mode = FIQ_MODE_NONE ;
368
+ hw -> fiq_claimed = 0 ;
369
+ } else {
370
+ hw -> fiq_claimed = 1 ;
371
+ }
372
+
373
+ return ret ;
374
+ }
375
+
376
+ /**
377
+ * s3c24xx_spi_initfiq - setup the information for the FIQ core
378
+ * @hw: The hardware state.
379
+ *
380
+ * Setup the fiq_handler block to pass to the FIQ core.
381
+ */
382
+ static inline void s3c24xx_spi_initfiq (struct s3c24xx_spi * hw )
383
+ {
384
+ hw -> fiq_handler .dev_id = hw ;
385
+ hw -> fiq_handler .name = dev_name (hw -> dev );
386
+ hw -> fiq_handler .fiq_op = s3c24xx_spi_fiqop ;
387
+ }
388
+
389
+ /**
390
+ * s3c24xx_spi_usefiq - return if we should be using FIQ.
391
+ * @hw: The hardware state.
392
+ *
393
+ * Return true if the platform data specifies whether this channel is
394
+ * allowed to use the FIQ.
395
+ */
396
+ static inline bool s3c24xx_spi_usefiq (struct s3c24xx_spi * hw )
397
+ {
398
+ return hw -> pdata -> use_fiq ;
399
+ }
400
+
401
+ /**
402
+ * s3c24xx_spi_usingfiq - return if channel is using FIQ
403
+ * @spi: The hardware state.
404
+ *
405
+ * Return whether the channel is currently using the FIQ (separate from
406
+ * whether the FIQ is claimed).
407
+ */
408
+ static inline bool s3c24xx_spi_usingfiq (struct s3c24xx_spi * spi )
409
+ {
410
+ return spi -> fiq_inuse ;
411
+ }
412
+ #else
413
+
414
+ static inline void s3c24xx_spi_initfiq (struct s3c24xx_spi * s ) { }
415
+ static inline void s3c24xx_spi_tryfiq (struct s3c24xx_spi * s ) { }
416
+ static inline bool s3c24xx_spi_usefiq (struct s3c24xx_spi * s ) { return false; }
417
+ static inline bool s3c24xx_spi_usingfiq (struct s3c24xx_spi * s ) { return false; }
418
+
419
+ #endif /* CONFIG_SPI_S3C24XX_FIQ */
420
+
217
421
static int s3c24xx_spi_txrx (struct spi_device * spi , struct spi_transfer * t )
218
422
{
219
423
struct s3c24xx_spi * hw = to_hw (spi );
220
424
221
- dev_dbg (& spi -> dev , "txrx: tx %p, rx %p, len %d\n" ,
222
- t -> tx_buf , t -> rx_buf , t -> len );
223
-
224
425
hw -> tx = t -> tx_buf ;
225
426
hw -> rx = t -> rx_buf ;
226
427
hw -> len = t -> len ;
227
428
hw -> count = 0 ;
228
429
229
430
init_completion (& hw -> done );
230
431
432
+ hw -> fiq_inuse = 0 ;
433
+ if (s3c24xx_spi_usefiq (hw ) && t -> len >= 3 )
434
+ s3c24xx_spi_tryfiq (hw );
435
+
231
436
/* send the first byte */
232
437
writeb (hw_txbyte (hw , 0 ), hw -> regs + S3C2410_SPTDAT );
233
438
234
439
wait_for_completion (& hw -> done );
235
-
236
440
return hw -> count ;
237
441
}
238
442
@@ -254,17 +458,27 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
254
458
goto irq_done ;
255
459
}
256
460
257
- hw -> count ++ ;
461
+ if (!s3c24xx_spi_usingfiq (hw )) {
462
+ hw -> count ++ ;
258
463
259
- if (hw -> rx )
260
- hw -> rx [count ] = readb (hw -> regs + S3C2410_SPRDAT );
464
+ if (hw -> rx )
465
+ hw -> rx [count ] = readb (hw -> regs + S3C2410_SPRDAT );
261
466
262
- count ++ ;
467
+ count ++ ;
468
+
469
+ if (count < hw -> len )
470
+ writeb (hw_txbyte (hw , count ), hw -> regs + S3C2410_SPTDAT );
471
+ else
472
+ complete (& hw -> done );
473
+ } else {
474
+ hw -> count = hw -> len ;
475
+ hw -> fiq_inuse = 0 ;
476
+
477
+ if (hw -> rx )
478
+ hw -> rx [hw -> len - 1 ] = readb (hw -> regs + S3C2410_SPRDAT );
263
479
264
- if (count < hw -> len )
265
- writeb (hw_txbyte (hw , count ), hw -> regs + S3C2410_SPTDAT );
266
- else
267
480
complete (& hw -> done );
481
+ }
268
482
269
483
irq_done :
270
484
return IRQ_HANDLED ;
@@ -322,6 +536,10 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
322
536
platform_set_drvdata (pdev , hw );
323
537
init_completion (& hw -> done );
324
538
539
+ /* initialise fiq handler */
540
+
541
+ s3c24xx_spi_initfiq (hw );
542
+
325
543
/* setup the master state. */
326
544
327
545
/* the spi->mode bits understood by this driver: */
0 commit comments