1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (c) 2007 Will Robertson
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include "spi-imx31.h"
24 #include "avic-imx31.h"
25 #include "ccm-imx31.h"
29 /* Forward interrupt handler declarations */
30 #if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
31 static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void);
33 #if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
34 static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void);
36 #if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
37 static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void);
40 #define RXDATA (0x000 / sizeof (unsigned long)) /* 000h */
41 #define TXDATA (0x004 / sizeof (unsigned long)) /* 004h */
42 #define CONREG (0x008 / sizeof (unsigned long)) /* 008h */
43 #define INTREG (0x00c / sizeof (unsigned long)) /* 00Ch */
44 #define DMAREG (0x010 / sizeof (unsigned long)) /* 010h */
45 #define STATREG (0x014 / sizeof (unsigned long)) /* 014h */
46 #define PERIODREG (0x01c / sizeof (unsigned long)) /* 018h */
47 #define TESTREG (0x1c0 / sizeof (unsigned long)) /* 1C0h */
49 /* State data associatated with each CSPI module */
50 static struct spi_module_desc
52 volatile unsigned long * const base
; /* CSPI module address */
53 struct spi_transfer_desc
*head
; /* Running job */
54 struct spi_transfer_desc
*tail
; /* Most recent job added */
55 const struct spi_node
*last_node
; /* Last node used for module */
56 void (* const handler
)(void); /* Interrupt handler */
57 int rxcount
; /* Independent copy of txcount */
58 int8_t enab
; /* Enable count */
59 int8_t byte_size
; /* Size of transfers in bytes */
60 const int8_t cg
; /* Clock-gating value */
61 const int8_t ints
; /* AVIC vector number */
62 } spi_descs
[SPI_NUM_CSPI
] =
63 /* Init non-zero members */
65 #if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
67 .base
= (unsigned long *)CSPI1_BASE_ADDR
,
70 .handler
= CSPI1_HANDLER
,
73 #if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
75 .base
= (unsigned long *)CSPI2_BASE_ADDR
,
78 .handler
= CSPI2_HANDLER
,
81 #if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
83 .base
= (unsigned long *)CSPI3_BASE_ADDR
,
86 .handler
= CSPI3_HANDLER
,
91 /* Reset the module */
92 static void spi_reset(struct spi_module_desc
* const desc
)
94 /* Reset by leaving it disabled */
95 desc
->base
[CONREG
] &= ~CSPI_CONREG_EN
;
98 /* Write the context for the node and remember it to avoid unneeded reconfigure */
99 static bool spi_set_context(struct spi_module_desc
*desc
,
100 struct spi_transfer_desc
*xfer
)
102 const struct spi_node
* const node
= xfer
->node
;
103 volatile unsigned long * const base
= desc
->base
;
108 if (node
== desc
->last_node
)
111 /* Errata says CSPI should be disabled when writing PERIODREG. */
112 base
[CONREG
] &= ~CSPI_CONREG_EN
;
114 /* Switch the module's node */
115 desc
->last_node
= node
;
116 desc
->byte_size
= (((node
->conreg
>> 8) & 0x1f) + 1 + 7) / 8 - 1;
118 /* Set the wait-states */
119 base
[PERIODREG
] = node
->periodreg
& 0xffff;
121 /* Keep reserved and start bits cleared. Keep enabled bit. */
123 (node
->conreg
& ~(0xfcc8e000 | CSPI_CONREG_XCH
| CSPI_CONREG_SMC
));
128 /* Fill the TX fifo. Returns the number of remaining words. */
129 static int tx_fill_fifo(struct spi_module_desc
* const desc
,
130 volatile unsigned long * const base
,
131 struct spi_transfer_desc
* const xfer
)
133 int count
= xfer
->count
;
134 int size
= desc
->byte_size
;
136 while ((base
[STATREG
] & CSPI_STATREG_TF
) == 0)
143 word
= *(unsigned char *)(xfer
->txbuf
+ 3) << 24;
145 word
|= *(unsigned char *)(xfer
->txbuf
+ 2) << 16;
147 word
|= *(unsigned char *)(xfer
->txbuf
+ 1) << 8;
149 word
|= *(unsigned char *)(xfer
->txbuf
+ 0);
152 xfer
->txbuf
+= size
+ 1; /* Increment buffer */
154 base
[TXDATA
] = word
; /* Write to FIFO */
165 /* Start a transfer on the SPI */
166 static bool start_transfer(struct spi_module_desc
* const desc
,
167 struct spi_transfer_desc
* const xfer
)
169 volatile unsigned long * const base
= desc
->base
;
170 unsigned long intreg
;
172 if (!spi_set_context(desc
, xfer
))
175 base
[CONREG
] |= CSPI_CONREG_EN
; /* Enable module */
177 desc
->rxcount
= xfer
->count
;
179 intreg
= (xfer
->count
< 8) ?
180 CSPI_INTREG_TCEN
: /* Trans. complete: TX will run out in prefill */
181 CSPI_INTREG_THEN
; /* INT when TX half-empty */
183 intreg
|= (xfer
->count
< 4) ?
184 CSPI_INTREG_RREN
: /* Must grab data on every word */
185 CSPI_INTREG_RHEN
; /* Enough data to wait for half-full */
187 tx_fill_fifo(desc
, base
, xfer
);
189 base
[STATREG
] = CSPI_STATREG_TC
; /* Ack 'complete' */
190 base
[INTREG
] = intreg
; /* Enable interrupts */
191 base
[CONREG
] |= CSPI_CONREG_XCH
; /* Begin transfer */
196 /* Common code for interrupt handlers */
197 static void spi_interrupt(enum spi_module_number spi
)
199 struct spi_module_desc
*desc
= &spi_descs
[spi
];
200 volatile unsigned long * const base
= desc
->base
;
201 unsigned long intreg
= base
[INTREG
];
202 struct spi_transfer_desc
*xfer
= desc
->head
;
203 int inc
= desc
->byte_size
+ 1;
205 /* Data received - empty out RXFIFO */
206 while ((base
[STATREG
] & CSPI_STATREG_RR
) != 0)
208 uint32_t word
= base
[RXDATA
];
210 if (desc
->rxcount
<= 0)
213 if (xfer
->rxbuf
!= NULL
)
215 /* There is a receive buffer */
216 switch (desc
->byte_size
& 3)
219 *(unsigned char *)(xfer
->rxbuf
+ 3) = word
>> 24;
221 *(unsigned char *)(xfer
->rxbuf
+ 2) = word
>> 16;
223 *(unsigned char *)(xfer
->rxbuf
+ 1) = word
>> 8;
225 *(unsigned char *)(xfer
->rxbuf
+ 0) = word
;
231 if (--desc
->rxcount
< 4)
233 if (desc
->rxcount
== 0)
235 /* No more to receive - stop RX interrupts */
236 intreg
&= ~(CSPI_INTREG_RHEN
| CSPI_INTREG_RREN
);
237 base
[INTREG
] = intreg
;
239 else if (intreg
& CSPI_INTREG_RHEN
)
241 /* < 4 words expected - switch to RX ready */
242 intreg
&= ~CSPI_INTREG_RHEN
;
243 intreg
|= CSPI_INTREG_RREN
;
244 base
[INTREG
] = intreg
;
251 /* Data to transmit - fill TXFIFO or write until exhausted. */
252 if (tx_fill_fifo(desc
, base
, xfer
) != 0)
255 /* Out of data - stop TX interrupts, enable TC interrupt. */
256 intreg
&= ~CSPI_INTREG_THEN
;
257 intreg
|= CSPI_INTREG_TCEN
;
258 base
[INTREG
] = intreg
;
261 if ((intreg
& CSPI_INTREG_TCEN
) && (base
[STATREG
] & CSPI_STATREG_TC
))
263 /* Outbound transfer is complete. */
264 intreg
&= ~CSPI_INTREG_TCEN
;
265 base
[INTREG
] = intreg
;
266 base
[STATREG
] = CSPI_STATREG_TC
; /* Ack 'complete' */
272 /* All interrupts are masked; we're done with current transfer. */
275 struct spi_transfer_desc
*next
= xfer
->next
;
276 spi_transfer_cb_fn_type callback
= xfer
->callback
;
279 base
[CONREG
] &= ~CSPI_CONREG_EN
; /* Disable module */
283 /* Last job on queue */
286 if (callback
!= NULL
)
289 /* Callback may have restarted transfers. */
293 /* Queue next job. */
296 if (callback
!= NULL
)
299 if (!start_transfer(desc
, next
))
303 continue; /* Failed: try next */
311 /* Interrupt handlers for each CSPI module */
312 #if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
313 static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void)
315 spi_interrupt(CSPI1_NUM
);
319 #if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
320 static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void)
322 spi_interrupt(CSPI2_NUM
);
326 #if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
327 static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void)
329 spi_interrupt(CSPI3_NUM
);
333 /* Initialize the SPI driver */
337 for (i
= 0; i
< SPI_NUM_CSPI
; i
++)
339 struct spi_module_desc
* const desc
= &spi_descs
[i
];
340 ccm_module_clock_gating(desc
->cg
, CGM_ON_RUN_WAIT
);
342 ccm_module_clock_gating(desc
->cg
, CGM_OFF
);
346 /* Enable the specified module for the node */
347 void spi_enable_module(const struct spi_node
*node
)
349 struct spi_module_desc
* const desc
= &spi_descs
[node
->num
];
351 if (++desc
->enab
== 1)
353 /* Enable clock-gating register */
354 ccm_module_clock_gating(desc
->cg
, CGM_ON_RUN_WAIT
);
357 desc
->last_node
= NULL
;
358 /* Enable interrupt at controller level */
359 avic_enable_int(desc
->ints
, INT_TYPE_IRQ
, INT_PRIO_DEFAULT
,
364 /* Disable the specified module for the node */
365 void spi_disable_module(const struct spi_node
*node
)
367 struct spi_module_desc
* const desc
= &spi_descs
[node
->num
];
369 if (desc
->enab
> 0 && --desc
->enab
== 0)
371 /* Last enable for this module */
372 /* Wait for outstanding transactions */
373 while (*(void ** volatile)&desc
->head
!= NULL
);
375 /* Disable interrupt at controller level */
376 avic_disable_int(desc
->ints
);
378 /* Disable interface */
379 desc
->base
[CONREG
] &= ~CSPI_CONREG_EN
;
381 /* Disable interface clock */
382 ccm_module_clock_gating(desc
->cg
, CGM_OFF
);
386 /* Send and/or receive data on the specified node */
387 bool spi_transfer(struct spi_transfer_desc
*xfer
)
390 struct spi_module_desc
* desc
;
393 if (xfer
->count
== 0)
394 return true; /* No data? No problem. */
396 if (xfer
->count
< 0 || xfer
->next
!= NULL
|| xfer
->node
== NULL
)
398 /* Can't pass a busy descriptor, requires a node and negative size
399 * is invalid to pass. */
403 oldlevel
= disable_irq_save();
405 desc
= &spi_descs
[xfer
->node
->num
];
407 if (desc
->head
== NULL
)
409 /* No transfers in progress; start interface. */
410 retval
= start_transfer(desc
, xfer
);
414 /* Start ok: actually put it in the queue. */
417 xfer
->next
= xfer
; /* First, self-reference terminate */
421 xfer
->count
= -1; /* Signal error */
426 /* Already running: simply add to end and the final INT on the
427 * running transfer will pick it up. */
428 desc
->tail
->next
= xfer
; /* Add to tail */
429 desc
->tail
= xfer
; /* New tail */
430 xfer
->next
= xfer
; /* Self-reference terminate */
434 restore_irq(oldlevel
);