i.MX31: Make some style changes to some driver code so that hardware vs. variable...
[kugel-rb.git] / firmware / target / arm / imx31 / spi-imx31.c
blobe6dddd65c15da9de504f6bcdb9ad10532e00f116
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "config.h"
22 #include "system.h"
23 #include "spi-imx31.h"
24 #include "avic-imx31.h"
25 #include "ccm-imx31.h"
26 #include "debug.h"
27 #include "kernel.h"
29 /* Forward interrupt handler declarations */
30 #if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
31 static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void);
32 #endif
33 #if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
34 static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void);
35 #endif
36 #if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
37 static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void);
38 #endif
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,
68 .cg = CG_CSPI1,
69 .ints = INT_CSPI1,
70 .handler = CSPI1_HANDLER,
72 #endif
73 #if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
75 .base = (unsigned long *)CSPI2_BASE_ADDR,
76 .cg = CG_CSPI2,
77 .ints = INT_CSPI2,
78 .handler = CSPI2_HANDLER,
80 #endif
81 #if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
83 .base = (unsigned long *)CSPI3_BASE_ADDR,
84 .cg = CG_CSPI3,
85 .ints = INT_CSPI3,
86 .handler = CSPI3_HANDLER,
88 #endif
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;
105 if (desc->enab == 0)
106 return false;
108 if (node == desc->last_node)
109 return true;
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. */
122 base[CONREG] =
123 (node->conreg & ~(0xfcc8e000 | CSPI_CONREG_XCH | CSPI_CONREG_SMC));
124 return true;
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)
138 uint32_t word = 0;
140 switch (size & 3)
142 case 3:
143 word = *(unsigned char *)(xfer->txbuf + 3) << 24;
144 case 2:
145 word |= *(unsigned char *)(xfer->txbuf + 2) << 16;
146 case 1:
147 word |= *(unsigned char *)(xfer->txbuf + 1) << 8;
148 case 0:
149 word |= *(unsigned char *)(xfer->txbuf + 0);
152 xfer->txbuf += size + 1; /* Increment buffer */
154 base[TXDATA] = word; /* Write to FIFO */
156 if (--count == 0)
157 break;
160 xfer->count = count;
162 return count;
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))
173 return false;
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 */
193 return true;
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)
211 continue;
213 if (xfer->rxbuf != NULL)
215 /* There is a receive buffer */
216 switch (desc->byte_size & 3)
218 case 3:
219 *(unsigned char *)(xfer->rxbuf + 3) = word >> 24;
220 case 2:
221 *(unsigned char *)(xfer->rxbuf + 2) = word >> 16;
222 case 1:
223 *(unsigned char *)(xfer->rxbuf + 1) = word >> 8;
224 case 0:
225 *(unsigned char *)(xfer->rxbuf + 0) = word;
228 xfer->rxbuf += inc;
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;
249 if (xfer->count > 0)
251 /* Data to transmit - fill TXFIFO or write until exhausted. */
252 if (tx_fill_fifo(desc, base, xfer) != 0)
253 return;
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' */
269 if (intreg != 0)
270 return;
272 /* All interrupts are masked; we're done with current transfer. */
273 for (;;)
275 struct spi_transfer_desc *next = xfer->next;
276 spi_transfer_cb_fn_type callback = xfer->callback;
277 xfer->next = NULL;
279 base[CONREG] &= ~CSPI_CONREG_EN; /* Disable module */
281 if (next == xfer)
283 /* Last job on queue */
284 desc->head = NULL;
286 if (callback != NULL)
287 callback(xfer);
289 /* Callback may have restarted transfers. */
291 else
293 /* Queue next job. */
294 desc->head = next;
296 if (callback != NULL)
297 callback(xfer);
299 if (!start_transfer(desc, next))
301 xfer = next;
302 xfer->count = -1;
303 continue; /* Failed: try next */
307 break;
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);
317 #endif
319 #if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
320 static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void)
322 spi_interrupt(CSPI2_NUM);
324 #endif
326 #if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
327 static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void)
329 spi_interrupt(CSPI3_NUM);
331 #endif
333 /* Initialize the SPI driver */
334 void spi_init(void)
336 unsigned i;
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);
341 spi_reset(desc);
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);
355 /* Reset */
356 spi_reset(desc);
357 desc->last_node = NULL;
358 /* Enable interrupt at controller level */
359 avic_enable_int(desc->ints, INT_TYPE_IRQ, INT_PRIO_DEFAULT,
360 desc->handler);
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)
389 bool retval;
390 struct spi_module_desc * desc;
391 int oldlevel;
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. */
400 return false;
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);
412 if (retval)
414 /* Start ok: actually put it in the queue. */
415 desc->head = xfer;
416 desc->tail = xfer;
417 xfer->next = xfer; /* First, self-reference terminate */
419 else
421 xfer->count = -1; /* Signal error */
424 else
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 */
431 retval = true;
434 restore_irq(oldlevel);
436 return retval;