summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/spi-imx31.c')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/spi-imx31.c355
1 files changed, 307 insertions, 48 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c
index 10ee3f44c0..bcbe85a76b 100644
--- a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c
@@ -18,66 +18,325 @@
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "cpu.h" 19#include "cpu.h"
20#include "spi-imx31.h" 20#include "spi-imx31.h"
21#include "avic-imx31.h"
22#include "clkctl-imx31.h"
21#include "debug.h" 23#include "debug.h"
22#include "kernel.h" 24#include "kernel.h"
23 25
24 /* This is all based on communicating with the MC13783 PMU which is on 26/* Forward interrupt handler declarations */
25 * CSPI2 with the chip select at 0. The LCD controller resides on 27#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
26 * CSPI3 cs1, but we have no idea how to communicate to it */ 28static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void);
27 29#endif
28void spi_init(void) { 30#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
29 CSPI_CONREG2 |= (2 << 20); // Burst will be triggered at SPI_RDY low 31static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void);
30 CSPI_CONREG2 |= (2 << 16); // Clock = IPG_CLK/16 - we want about 20mhz 32#endif
31 CSPI_CONREG2 |= (31 << 8); // All 32 bits are to be transferred 33#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
32 CSPI_CONREG2 |= (1 << 3); // Start burst on TXFIFO write. 34static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void);
33 CSPI_CONREG2 |= (1 << 1); // Master mode. 35#endif
34 CSPI_CONREG2 |= 1; // Enable CSPI2; 36
37/* State data associatated with each CSPI module */
38static struct spi_module_descriptor
39{
40 volatile unsigned long *base;
41 int enab;
42 struct spi_node *last;
43 enum IMX31_CG_LIST cg;
44 enum IMX31_INT_LIST ints;
45 int byte_size;
46 void (*handler)(void);
47 struct mutex m;
48 struct wakeup w;
49 struct spi_transfer *trans;
50 int rxcount;
51} spi_descs[SPI_NUM_CSPI] =
52/* Init non-zero members */
53{
54#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
55 {
56 .base = (unsigned long *)CSPI1_BASE_ADDR,
57 .cg = CG_CSPI1,
58 .ints = CSPI1,
59 .handler = CSPI1_HANDLER,
60 },
61#endif
62#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
63 {
64 .base = (unsigned long *)CSPI2_BASE_ADDR,
65 .cg = CG_CSPI2,
66 .ints = CSPI2,
67 .handler = CSPI2_HANDLER,
68 },
69#endif
70#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
71 {
72 .base = (unsigned long *)CSPI3_BASE_ADDR,
73 .cg = CG_CSPI3,
74 .ints = CSPI3,
75 .handler = CSPI3_HANDLER,
76 },
77#endif
78};
79
80/* Common code for interrupt handlers */
81static void spi_interrupt(enum spi_module_number spi)
82{
83 struct spi_module_descriptor *desc = &spi_descs[spi];
84 volatile unsigned long * const base = desc->base;
85 struct spi_transfer *trans = desc->trans;
86 int inc = desc->byte_size + 1;
87
88 if (desc->rxcount > 0)
89 {
90 /* Data received - empty out RXFIFO */
91 while ((base[CSPI_STATREG_I] & CSPI_STATREG_RR) != 0)
92 {
93 uint32_t word = base[CSPI_RXDATA_I];
94
95 switch (desc->byte_size & 3)
96 {
97 case 3:
98 *(unsigned char *)(trans->rxbuf + 3) = word >> 24;
99 case 2:
100 *(unsigned char *)(trans->rxbuf + 2) = word >> 16;
101 case 1:
102 *(unsigned char *)(trans->rxbuf + 1) = word >> 8;
103 case 0:
104 *(unsigned char *)(trans->rxbuf + 0) = word;
105 }
106
107 trans->rxbuf += inc;
108
109 if (--desc->rxcount < 4)
110 {
111 unsigned long intreg = base[CSPI_INTREG_I];
112
113 if (desc->rxcount <= 0)
114 {
115 /* No more to receive - stop RX interrupts */
116 intreg &= ~(CSPI_INTREG_RHEN | CSPI_INTREG_RREN);
117 base[CSPI_INTREG_I] = intreg;
118 break;
119 }
120 else if (!(intreg & CSPI_INTREG_RREN))
121 {
122 /* < 4 words expected - switch to RX ready */
123 intreg &= ~CSPI_INTREG_RHEN;
124 base[CSPI_INTREG_I] = intreg | CSPI_INTREG_RREN;
125 }
126 }
127 }
128 }
129
130 if (trans->count > 0)
131 {
132 /* Data to transmit - fill TXFIFO or write until exhausted */
133 while ((base[CSPI_STATREG_I] & CSPI_STATREG_TF) == 0)
134 {
135 uint32_t word = 0;
136
137 switch (desc->byte_size & 3)
138 {
139 case 3:
140 word = *(unsigned char *)(trans->txbuf + 3) << 24;
141 case 2:
142 word |= *(unsigned char *)(trans->txbuf + 2) << 16;
143 case 1:
144 word |= *(unsigned char *)(trans->txbuf + 1) << 8;
145 case 0:
146 word |= *(unsigned char *)(trans->txbuf + 0);
147 }
148
149 trans->txbuf += inc;
150
151 base[CSPI_TXDATA_I] = word;
152
153 if (--trans->count <= 0)
154 {
155 /* Out of data - stop TX interrupts */
156 base[CSPI_INTREG_I] &= ~CSPI_INTREG_THEN;
157 break;
158 }
159 }
160 }
161
162 /* If all interrupts have been remasked - we're done */
163 if (base[CSPI_INTREG_I] == 0)
164 {
165 base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO;
166 wakeup_signal(&desc->w);
167 }
168}
169
170/* Interrupt handlers for each CSPI module */
171#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
172static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void)
173{
174 spi_interrupt(CSPI1_NUM);
175}
176#endif
177
178#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
179static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void)
180{
181 spi_interrupt(CSPI2_NUM);
182}
183#endif
184
185#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
186static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void)
187{
188 spi_interrupt(CSPI3_NUM);
189}
190#endif
191
192/* Write the context for the node and remember it to avoid unneeded reconfigure */
193static bool spi_set_context(struct spi_node *node,
194 struct spi_module_descriptor *desc)
195{
196 volatile unsigned long * const base = desc->base;
197
198 if ((base[CSPI_CONREG_I] & CSPI_CONREG_EN) == 0)
199 return false;
200
201 if (node != desc->last)
202 {
203 /* Switch the module's node */
204 desc->last = node;
205 desc->byte_size = (((node->conreg >> 8) & 0x1f) + 1 + 7) / 8 - 1;
206
207 /* Keep reserved and start bits cleared. Keep enabled bit. */
208 base[CSPI_CONREG_I] =
209 (node->conreg & ~(0xfcc8e000 | CSPI_CONREG_XCH | CSPI_CONREG_SMC))
210 | CSPI_CONREG_EN;
211 /* Set the wait-states */
212 base[CSPI_PERIODREG_I] = node->periodreg & 0xffff;
213 /* Clear out any spuriously-pending interrupts */
214 base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO;
215 }
216
217 return true;
35} 218}
36 219
37static int spi_transfer(int address, long data, long* buffer, bool read) { 220/* Initialize each of the used SPI descriptors */
38 return -1; /* Disable for now - hangs - and we'll use interrupts */ 221void spi_init(void)
222{
223 int i;
39 224
40 unsigned long packet = 0; 225 for (i = 0; i < SPI_NUM_CSPI; i++)
41 if(!read) { 226 {
42 /* Set the appropriate bit in the packet to indicate a write */ 227 struct spi_module_descriptor * const desc = &spi_descs[i];
43 packet |= (1<<31); 228 mutex_init(&desc->m);
229 wakeup_init(&desc->w);
44 } 230 }
45 /* Set the address of the packet */ 231}
46 packet |= (address << 25); 232
47 233/* Get mutually-exclusive access to the node */
48 /* Ensure data only occupies 24 bits, then mash the data into the packet */ 234void spi_lock(struct spi_node *node)
49 data &= ~(DATAMASK); 235{
50 packet |= data; 236 mutex_lock(&spi_descs[node->num].m);
51 237}
52 /* Wait for some room in TXFIFO */ 238
53 while(CSPI_STATREG2 & (1<<2)); 239/* Release mutual exclusion */
54 240void spi_unlock(struct spi_node *node)
55 /* Send the packet */ 241{
56 CSPI_TXDATA2 = packet; 242 mutex_unlock(&spi_descs[node->num].m);
57 243}
58 /* Poll the XCH bit to wait for the end of the transfer, with 244
59 * a one second timeout */ 245/* Enable the specified module for the node */
60 int newtick = current_tick + HZ; 246void spi_enable_module(struct spi_node *node)
61 while((CSPI_CONREG2 & (1<<2)) && (current_tick < newtick)); 247{
62 248 struct spi_module_descriptor * const desc = &spi_descs[node->num];
63 if(newtick > current_tick) { 249
64 *buffer = CSPI_RXDATA2; 250 mutex_lock(&desc->m);
65 return 0; 251
66 } else { 252 if (++desc->enab == 1)
67 /* Indicate the fact that the transfer timed out */ 253 {
68 return -1; 254 /* First enable for this module */
255 volatile unsigned long * const base = desc->base;
256
257 /* Enable clock-gating register */
258 imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
259
260 /* Reset */
261 base[CSPI_CONREG_I] &= ~CSPI_CONREG_EN;
262 base[CSPI_CONREG_I] |= CSPI_CONREG_EN;
263 base[CSPI_INTREG_I] = 0;
264 base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO;
265
266 /* Enable interrupt at controller level */
267 avic_enable_int(desc->ints, IRQ, 6, desc->handler);
69 } 268 }
269
270 mutex_unlock(&desc->m);
70} 271}
71 272
72void spi_send(int address, unsigned long data) { 273/* Disabled the specified module for the node */
73 long dummy; 274void spi_disable_module(struct spi_node *node)
74 if(spi_transfer(address, data, &dummy, false)) { 275{
75 DEBUGF("SPI Send timed out"); 276 struct spi_module_descriptor * const desc = &spi_descs[node->num];
277
278 mutex_lock(&desc->m);
279
280 if (desc->enab > 0 && --desc->enab == 0)
281 {
282 /* Last enable for this module */
283 volatile unsigned long * const base = desc->base;
284
285 /* Disable interrupt at controller level */
286 avic_disable_int(desc->ints);
287
288 /* Disable interface */
289 base[CSPI_CONREG_I] &= ~CSPI_CONREG_EN;
290
291 /* Disable interface clock */
292 imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
76 } 293 }
294
295 mutex_unlock(&desc->m);
77} 296}
78 297
79void spi_read(int address, unsigned long* buffer) { 298/* Send and/or receive data on the specified node */
80 if(spi_transfer(address, 0, buffer, true)) { 299int spi_transfer(struct spi_node *node, struct spi_transfer *trans)
81 DEBUGF("SPI read timed out"); 300{
301 struct spi_module_descriptor * const desc = &spi_descs[node->num];
302 int retval;
303
304 if (trans->count <= 0)
305 return true;
306
307 mutex_lock(&desc->m);
308
309 retval = spi_set_context(node, desc);
310
311 if (retval)
312 {
313 volatile unsigned long * const base = desc->base;
314 unsigned long intreg;
315
316 desc->trans = trans;
317 desc->rxcount = trans->count;
318
319 /* Enable needed interrupts - FIFOs will start filling */
320 intreg = CSPI_INTREG_THEN;
321
322 intreg |= (trans->count < 4) ?
323 CSPI_INTREG_RREN : /* Must grab data on every word */
324 CSPI_INTREG_RHEN; /* Enough data to wait for half-full */
325
326 base[CSPI_INTREG_I] = intreg;
327
328 /* Start transfer */
329 base[CSPI_CONREG_I] |= CSPI_CONREG_XCH;
330
331 if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED)
332 {
333 base[CSPI_INTREG_I] = 0;
334 base[CSPI_CONREG_I] &= ~CSPI_CONREG_XCH;
335 retval = false;
336 }
82 } 337 }
338
339 mutex_unlock(&desc->m);
340
341 return retval;
83} 342}