summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/spi-imx31.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-04-09 01:21:53 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-04-09 01:21:53 +0000
commit7abf2b53a462612808d46d6d77a7f35261a0e5a3 (patch)
tree241304f7cd2b5d1c2a9e091fe56a33d2d2f8e816 /firmware/target/arm/imx31/spi-imx31.c
parent43304b87b0662d1619ac60e5297a1694aa580310 (diff)
downloadrockbox-7abf2b53a462612808d46d6d77a7f35261a0e5a3.tar.gz
rockbox-7abf2b53a462612808d46d6d77a7f35261a0e5a3.zip
Gigabeat S/i.MX31: Sort files in the /target tree into things that are SoC-generic (into /imx31) and player-specific (into /gigabeat-s, based upon current appearances). Move i2s clock init into the appropriate file. Housekeeping only-- no functional changes.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25547 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx31/spi-imx31.c')
-rw-r--r--firmware/target/arm/imx31/spi-imx31.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/firmware/target/arm/imx31/spi-imx31.c b/firmware/target/arm/imx31/spi-imx31.c
new file mode 100644
index 0000000000..ac063f9b10
--- /dev/null
+++ b/firmware/target/arm/imx31/spi-imx31.c
@@ -0,0 +1,352 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2007 Will Robertson
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
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"
28
29/* Forward interrupt handler declarations */
30#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
31static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void);
32#endif
33#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
34static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void);
35#endif
36#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
37static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void);
38#endif
39
40/* State data associatated with each CSPI module */
41static struct spi_module_descriptor
42{
43 struct cspi_map * const base;
44 int enab;
45 struct spi_node *last;
46 enum IMX31_CG_LIST cg;
47 enum IMX31_INT_LIST ints;
48 int byte_size;
49 void (*handler)(void);
50 struct mutex m;
51 struct wakeup w;
52 struct spi_transfer *trans;
53 int rxcount;
54} spi_descs[SPI_NUM_CSPI] =
55/* Init non-zero members */
56{
57#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
58 {
59 .base = (struct cspi_map *)CSPI1_BASE_ADDR,
60 .cg = CG_CSPI1,
61 .ints = INT_CSPI1,
62 .handler = CSPI1_HANDLER,
63 },
64#endif
65#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
66 {
67 .base = (struct cspi_map *)CSPI2_BASE_ADDR,
68 .cg = CG_CSPI2,
69 .ints = INT_CSPI2,
70 .handler = CSPI2_HANDLER,
71 },
72#endif
73#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
74 {
75 .base = (struct cspi_map *)CSPI3_BASE_ADDR,
76 .cg = CG_CSPI3,
77 .ints = INT_CSPI3,
78 .handler = CSPI3_HANDLER,
79 },
80#endif
81};
82
83/* Common code for interrupt handlers */
84static void spi_interrupt(enum spi_module_number spi)
85{
86 struct spi_module_descriptor *desc = &spi_descs[spi];
87 struct cspi_map * const base = desc->base;
88 struct spi_transfer *trans = desc->trans;
89 int inc = desc->byte_size + 1;
90
91 if (desc->rxcount > 0)
92 {
93 /* Data received - empty out RXFIFO */
94 while ((base->statreg & CSPI_STATREG_RR) != 0)
95 {
96 uint32_t word = base->rxdata;
97
98 switch (desc->byte_size & 3)
99 {
100 case 3:
101 *(unsigned char *)(trans->rxbuf + 3) = word >> 24;
102 case 2:
103 *(unsigned char *)(trans->rxbuf + 2) = word >> 16;
104 case 1:
105 *(unsigned char *)(trans->rxbuf + 1) = word >> 8;
106 case 0:
107 *(unsigned char *)(trans->rxbuf + 0) = word;
108 }
109
110 trans->rxbuf += inc;
111
112 if (--desc->rxcount < 4)
113 {
114 unsigned long intreg = base->intreg;
115
116 if (desc->rxcount <= 0)
117 {
118 /* No more to receive - stop RX interrupts */
119 intreg &= ~(CSPI_INTREG_RHEN | CSPI_INTREG_RREN);
120 base->intreg = intreg;
121 break;
122 }
123 else if (!(intreg & CSPI_INTREG_RREN))
124 {
125 /* < 4 words expected - switch to RX ready */
126 intreg &= ~CSPI_INTREG_RHEN;
127 base->intreg = intreg | CSPI_INTREG_RREN;
128 }
129 }
130 }
131 }
132
133 if (trans->count > 0)
134 {
135 /* Data to transmit - fill TXFIFO or write until exhausted */
136 while ((base->statreg & CSPI_STATREG_TF) == 0)
137 {
138 uint32_t word = 0;
139
140 switch (desc->byte_size & 3)
141 {
142 case 3:
143 word = *(unsigned char *)(trans->txbuf + 3) << 24;
144 case 2:
145 word |= *(unsigned char *)(trans->txbuf + 2) << 16;
146 case 1:
147 word |= *(unsigned char *)(trans->txbuf + 1) << 8;
148 case 0:
149 word |= *(unsigned char *)(trans->txbuf + 0);
150 }
151
152 trans->txbuf += inc;
153
154 base->txdata = word;
155
156 if (--trans->count <= 0)
157 {
158 /* Out of data - stop TX interrupts */
159 base->intreg &= ~CSPI_INTREG_THEN;
160 break;
161 }
162 }
163 }
164
165 /* If all interrupts have been remasked - we're done */
166 if (base->intreg == 0)
167 {
168 base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO;
169 wakeup_signal(&desc->w);
170 }
171}
172
173/* Interrupt handlers for each CSPI module */
174#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
175static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void)
176{
177 spi_interrupt(CSPI1_NUM);
178}
179#endif
180
181#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
182static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void)
183{
184 spi_interrupt(CSPI2_NUM);
185}
186#endif
187
188#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
189static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void)
190{
191 spi_interrupt(CSPI3_NUM);
192}
193#endif
194
195/* Write the context for the node and remember it to avoid unneeded reconfigure */
196static bool spi_set_context(struct spi_node *node,
197 struct spi_module_descriptor *desc)
198{
199 struct cspi_map * const base = desc->base;
200
201 if ((base->conreg & CSPI_CONREG_EN) == 0)
202 return false;
203
204 if (node != desc->last)
205 {
206 /* Switch the module's node */
207 desc->last = node;
208 desc->byte_size = (((node->conreg >> 8) & 0x1f) + 1 + 7) / 8 - 1;
209
210 /* Keep reserved and start bits cleared. Keep enabled bit. */
211 base->conreg =
212 (node->conreg & ~(0xfcc8e000 | CSPI_CONREG_XCH | CSPI_CONREG_SMC))
213 | CSPI_CONREG_EN;
214 /* Set the wait-states */
215 base->periodreg = node->periodreg & 0xffff;
216 /* Clear out any spuriously-pending interrupts */
217 base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO;
218 }
219
220 return true;
221}
222
223static void spi_reset(struct cspi_map * const base)
224{
225 /* Reset */
226 base->conreg &= ~CSPI_CONREG_EN;
227 base->conreg |= CSPI_CONREG_EN;
228 base->intreg = 0;
229 base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO;
230}
231
232/* Initialize each of the used SPI descriptors */
233void spi_init(void)
234{
235 int i;
236
237 for (i = 0; i < SPI_NUM_CSPI; i++)
238 {
239 struct spi_module_descriptor * const desc = &spi_descs[i];
240 mutex_init(&desc->m);
241 wakeup_init(&desc->w);
242 }
243}
244
245/* Get mutually-exclusive access to the node */
246void spi_lock(struct spi_node *node)
247{
248 mutex_lock(&spi_descs[node->num].m);
249}
250
251/* Release mutual exclusion */
252void spi_unlock(struct spi_node *node)
253{
254 mutex_unlock(&spi_descs[node->num].m);
255}
256
257/* Enable the specified module for the node */
258void spi_enable_module(struct spi_node *node)
259{
260 struct spi_module_descriptor * const desc = &spi_descs[node->num];
261
262 mutex_lock(&desc->m);
263
264 if (++desc->enab == 1)
265 {
266 /* First enable for this module */
267 struct cspi_map * const base = desc->base;
268
269 /* Enable clock-gating register */
270 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT);
271 /* Reset */
272 spi_reset(base);
273 desc->last = NULL;
274 /* Enable interrupt at controller level */
275 avic_enable_int(desc->ints, INT_TYPE_IRQ, INT_PRIO_DEFAULT,
276 desc->handler);
277 }
278
279 mutex_unlock(&desc->m);
280}
281
282/* Disabled the specified module for the node */
283void spi_disable_module(struct spi_node *node)
284{
285 struct spi_module_descriptor * const desc = &spi_descs[node->num];
286
287 mutex_lock(&desc->m);
288
289 if (desc->enab > 0 && --desc->enab == 0)
290 {
291 /* Last enable for this module */
292 struct cspi_map * const base = desc->base;
293
294 /* Disable interrupt at controller level */
295 avic_disable_int(desc->ints);
296
297 /* Disable interface */
298 base->conreg &= ~CSPI_CONREG_EN;
299
300 /* Disable interface clock */
301 ccm_module_clock_gating(desc->cg, CGM_OFF);
302 }
303
304 mutex_unlock(&desc->m);
305}
306
307/* Send and/or receive data on the specified node */
308int spi_transfer(struct spi_node *node, struct spi_transfer *trans)
309{
310 struct spi_module_descriptor * const desc = &spi_descs[node->num];
311 int retval;
312
313 if (trans->count <= 0)
314 return true;
315
316 mutex_lock(&desc->m);
317
318 retval = spi_set_context(node, desc);
319
320 if (retval)
321 {
322 struct cspi_map * const base = desc->base;
323 unsigned long intreg;
324
325 desc->trans = trans;
326 desc->rxcount = trans->count;
327
328 /* Enable needed interrupts - FIFOs will start filling */
329 intreg = CSPI_INTREG_THEN;
330
331 intreg |= (trans->count < 4) ?
332 CSPI_INTREG_RREN : /* Must grab data on every word */
333 CSPI_INTREG_RHEN; /* Enough data to wait for half-full */
334
335 base->intreg = intreg;
336
337 /* Start transfer */
338 base->conreg |= CSPI_CONREG_XCH;
339
340 if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED)
341 {
342 base->intreg = 0; /* Stop SPI ints */
343 spi_reset(base); /* Reset module (esp. to empty FIFOs) */
344 desc->last = NULL; /* Force reconfigure */
345 retval = false;
346 }
347 }
348
349 mutex_unlock(&desc->m);
350
351 return retval;
352}