]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blob - rpp/lib/rpp/src/hal/spi_tms570.c
Yet another place to fix
[pes-rpp/rpp-test-sw.git] / rpp / lib / rpp / src / hal / spi_tms570.c
1 /* Code based on Halcogen generated source code */
2
3 //#include "spi_tms570.h"
4 //#include "drv_spi.h"
5 //#include "sys_common.h"
6 //#include "ti_drv_dmm.h"
7 #include "hal/hal.h"
8
9 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
10
11
12 /* Each SPI interface has its own static spi_tms570_drv_t struct
13    Index to this array is "SPI Interface ID -1" */
14 spi_tms570_drv_t spi_tms570_ifcs[4];
15
16 /* Addresses of SPI devices (=chips) bound to particular interfaces */
17 enum spi_ifc1_devices { SPIDEV_MC33972 = 0, SPIDEV_NCV7608_2x };
18 enum spi_ifc2_devices { SPIDEV_SDCARD = 0};
19 enum spi_ifc3_devices { SPIDEV_MCP4922_1 = 0, SPIDEV_MCP4922_2, SPIDEV_MCP4922_3 };
20 enum spi_ifc4_devices { SPIDEV_L99H01 = 0, SPIDEV_TJA1082_1, SPIDEV_TJA1082_2 };
21
22 spi_dev_t spi_ifc1_devs[] = {
23     [SPIDEV_MC33972] = {
24         .cs = SPI_CS_3,
25         .dfsel = 0,
26         .wdel = 0,
27         .cshold = 1,
28         .dlen = 0},
29     [SPIDEV_NCV7608_2x] = {
30         .cs = SPI_CS_4,
31         .dfsel = 0,
32         .wdel = 0,
33         .cshold = 1,
34         .dlen = 0}
35 };
36
37 spi_dev_t spi_ifc2_devs[] = {
38     [SPIDEV_SDCARD] = {
39         .cs = SPI_CS_0,
40         .dfsel = 0,
41         .wdel = 0,
42         .cshold = 1,
43         .dlen = 0}
44 };
45
46 spi_dev_t spi_ifc3_devs[] = {
47     [SPIDEV_MCP4922_1] = {
48         .cs = SPI_CS_0,
49         .dfsel = 1,
50         .wdel = 0,
51         .cshold = 1,
52         .dlen = 0},
53     [SPIDEV_MCP4922_2] = {
54         .cs = SPI_CS_4,
55         .dfsel = 1,
56         .wdel = 0,
57         .cshold = 1,
58         .dlen = 0},
59     [SPIDEV_MCP4922_3] = {
60         .cs = SPI_CS_5,
61         .dfsel = 1,
62         .wdel = 0,
63         .cshold = 1,
64         .dlen = 0}
65 };
66
67 spi_dev_t spi_ifc4_devs[] = {
68     [SPIDEV_L99H01] = {
69         .cs = SPI_CS_0 | SPI_CS_DMM0,
70         .dfsel = 1,
71         .wdel = 0,
72         .cshold = 1,
73         .dlen = 0},
74     [SPIDEV_TJA1082_1] = {
75         .cs = SPI_CS_0 | SPI_CS_DMM1,
76         .dfsel = 0,
77         .wdel = 0,
78         .cshold = 1,
79         .dlen = 0},
80     [SPIDEV_TJA1082_2] = {
81         .cs = SPI_CS_0 | SPI_CS_DMM2,
82         .dfsel = 0,
83         .wdel = 0,
84         .cshold = 1,
85         .dlen = 0}
86 };
87
88 /*
89  Universal piece of code initializing SPI or MibSPI
90  devices in "compatibility" mode.
91  8 CS pins are initialized on each device -- even if
92  it does not have so much of them.
93  ENA register is set even on SPI devices which do not have it --
94  this should not be an issue
95 */
96 void spiInit(spiBASE_compat_t *spiREG)
97 {
98     /** bring SPI out of reset */
99     spiREG->GCR0 = 1U;
100
101     /** SPI master mode and clock configuration */
102     spiREG->GCR1 = (1 << 1) /* CLOKMOD */
103         |1;         /* MASTER */
104
105     /** SPI enable pin configuration */
106     spiREG->ENAHIGHZ = 0;   /* ENABLE HIGHZ */
107
108     /** - Delays */
109     spiREG->DELAY = (0 << 24)   /* C2TDELAY */
110         | (0 << 16)     /* T2CDELAY */
111         | (0 << 8)      /* T2EDELAY */
112         | 0;            /* C2EDELAY */
113
114     /** - Data Format 0 */
115     spiREG->FMT0 = (0 << 24)    /* wdelay */
116         | (0 << 23)     /* parity Polarity */
117         | (0 << 22)     /* parity enable */
118         | (0 << 21)     /* wait on enable */
119         | (0 << 20)     /* shift direction */
120         | (0 << 17)     /* clock polarity */
121         | (0 << 16)     /* clock phase */
122         | (79 << 8)     /* baudrate prescale */
123         | 8;            /* data word length */
124
125     /** - Data Format 1 */
126     spiREG->FMT1 = (0 << 24)    /* wdelay */
127         | (0 << 23)     /* parity Polarity */
128         | (0 << 22)     /* parity enable */
129         | (0 << 21)     /* wait on enable */
130         | (0 << 20)     /* shift direction */
131         | (0 << 17)     /* clock polarity */
132         | (1 << 16)     /* clock phase */
133         | (79 << 8)     /* baudrate prescale */
134         | 8;        /* data word length */
135
136     /** - Data Format 2 */
137     spiREG->FMT2 = (0 << 24)    /* wdelay */
138         | (0 << 23)     /* parity Polarity */
139         | (0 << 22)     /* parity enable */
140         | (0 << 21)     /* wait on enable */
141         | (0 << 20)     /* shift direction */
142         | (0 << 17)     /* clock polarity */
143         | (0 << 16)     /* clock phase */
144         | (79 << 8)     /* baudrate prescale */
145         | 8;        /* data word length */
146
147     /** - Data Format 3 */
148     spiREG->FMT3 = (0 << 24)    /* wdelay */
149         | (0 << 23)     /* parity Polarity */
150         | (0 << 22)     /* parity enable */
151         | (0 << 21)     /* wait on enable */
152         | (0 << 20)     /* shift direction */
153         | (0 << 17)     /* clock polarity */
154         | (0 << 16)     /* clock phase */
155         | (79 << 8)     /* baudrate prescale */
156         | 8;        /* data word length */
157
158     /** - set interrupt levels */
159     spiREG->LVL = (0 << 9)  /* TXINT */
160         | (0 << 8)      /* RXINT */
161         | (0 << 6)      /* OVRNINT */
162         | (0 << 4)      /* BITERR */
163         | (0 << 3)      /* DESYNC */
164         | (0 << 2)      /* PARERR */
165         | (0 << 1)      /* TIMEOUT */
166         | (0);      /* DLENERR */
167
168     /** - clear any pending interrupts */
169     spiREG->FLG = 0xFFFFU;
170
171     /** - enable interrupts */
172     spiREG->INT0 = (0 << 9) /* TXINT */
173         | (0 << 8)      /* RXINT */
174         | (0 << 6)      /* OVRNINT */
175         | (0 << 4)      /* BITERR */
176         | (0 << 3)      /* DESYNC */
177         | (0 << 2)      /* PARERR */
178         | (0 << 1)      /* TIMEOUT */
179         | (0);      /* DLENERR */
180
181     /** initialize SPI Port */
182
183     /** - SPI Port output values */
184     spiREG->PCDOUT = 1  /* SCS[0] */
185         | (1 << 1)      /* SCS[1] */
186         | (1 << 2)      /* SCS[2] */
187         | (1 << 3)      /* SCS[3] */
188         | (1 << 4)      /* SCS[4] */
189         | (1 << 5)      /* SCS[5] */
190         | (1 << 6)      /* SCS[6] */
191         | (1 << 7)      /* SCS[7] */
192         | (0 << 8)      /* ENA */
193         | (0 << 9)      /* CLK */
194         | (0 << 10)     /* SIMO */
195         | (0 << 11);        /* SOMI */
196
197     /** - SPI Port direction */
198     spiREG->PCDIR = 1   /* SCS[0] */
199         | (1 << 1)      /* SCS[1] */
200         | (1 << 2)      /* SCS[2] */
201         | (1 << 3)      /* SCS[3] */
202         | (1 << 4)      /* SCS[4] */
203         | (1 << 5)      /* SCS[5] */
204         | (1 << 6)      /* SCS[6] */
205         | (1 << 7)      /* SCS[7] */
206         | (0 << 8)      /* ENA */
207         | (1 << 9)      /* CLK */
208         | (1 << 10)     /* SIMO */
209         | (0 << 11);        /* SOMI */
210
211     /** - SPI Port open drain enable */
212     spiREG->PCPDR = 0   /* SCS[0] */
213         | (0 << 1)      /* SCS[1] */
214         | (0 << 2)      /* SCS[2] */
215         | (0 << 3)      /* SCS[3] */
216         | (0 << 4)      /* SCS[4] */
217         | (0 << 5)      /* SCS[5] */
218         | (0 << 6)      /* SCS[6] */
219         | (0 << 7)      /* SCS[7] */
220         | (0 << 8)      /* ENA */
221         | (0 << 9)      /* CLK */
222         | (0 << 10)     /* SIMO */
223         | (0 << 11);    /* SOMI */
224
225     /** - SPI Port pullup / pulldown selection */
226     spiREG->PCPSL = 1   /* SCS[0] */
227         | (1 << 1)      /* SCS[1] */
228         | (1 << 2)      /* SCS[2] */
229         | (1 << 3)      /* SCS[3] */
230         | (1 << 4)      /* SCS[4] */
231         | (1 << 5)      /* SCS[5] */
232         | (1 << 6)      /* SCS[6] */
233         | (1 << 7)      /* SCS[7] */
234         | (1 << 8)      /* ENA */
235         | (1 << 9)      /* CLK */
236         | (1 << 10)     /* SIMO */
237         | (1 << 11);        /* SOMI */
238
239     /** - SPI Port pullup / pulldown enable*/
240     spiREG->PCDIS = 0   /* SCS[0] */
241         | (0 << 1)      /* SCS[1] */
242         | (0 << 2)      /* SCS[2] */
243         | (0 << 3)      /* SCS[3] */
244         | (0 << 4)      /* SCS[4] */
245         | (0 << 5)      /* SCS[5] */
246         | (0 << 6)      /* SCS[6] */
247         | (0 << 7)      /* SCS[7] */
248         | (0 << 8)      /* ENA */
249         | (0 << 9)      /* CLK */
250         | (0 << 10)     /* SIMO */
251         | (0 << 11);        /* SOMI */
252
253     /* SPI set all pins to functional */
254     spiREG->PCFUN = 1   /* SCS[0] */
255         | (1 << 1)      /* SCS[1] */
256         | (1 << 2)      /* SCS[2] */
257         | (1 << 3)      /* SCS[3] */
258         | (1 << 4)      /* SCS[4] */
259         | (1 << 5)      /* SCS[5] */
260         | (1 << 6)      /* SCS[6] */
261         | (1 << 7)      /* SCS[7] */
262         | (1 << 8)      /* ENA */
263         | (1 << 9)      /* CLK */
264         | (1 << 10)     /* SIMO */
265         | (1 << 11);    /* SOMI */
266
267     /* Default CS logic levels */
268     spiREG->CSDEF = 0xFF;
269
270     /** Set MibSPI devices into compatibility mode --
271         "SPI" devices will hopefully ignore this */
272     spiREG->MIBSPIE = 0U;
273
274     /** - Finally start SPI */
275     spiREG->ENA = 1U;
276 }
277
278
279 int spi_tms570_init(void)
280 {
281     int i;
282
283     spi_tms570_ifcs[0].spi = mibspi_compat_REG1;
284     spi_tms570_ifcs[1].spi = spi_compat_REG2;
285     spi_tms570_ifcs[2].spi = mibspi_compat_REG3;
286     spi_tms570_ifcs[3].spi = spi_compat_REG4;
287
288     spi_tms570_ifcs[0].spi_devs = spi_ifc1_devs;
289     spi_tms570_ifcs[1].spi_devs = spi_ifc2_devs;
290     spi_tms570_ifcs[2].spi_devs = spi_ifc3_devs;
291     spi_tms570_ifcs[3].spi_devs = spi_ifc4_devs;
292
293
294     for (i = 0; i <= 3; i++)
295     {
296         spiInit(spi_tms570_ifcs[i].spi);
297         spi_tms570_ifcs[i].spi_drv.ctrl_fnc = spi_tms570_ctrl_fnc;
298         spi_rq_queue_init_head(&(spi_tms570_ifcs[i].spi_drv));
299         spi_tms570_ifcs[i].spi_drv.msg_act = NULL;
300         spi_tms570_ifcs[i].spi_drv.flags = SPI_IFC_ON;
301     }
302
303     //dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
304     //dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
305
306     return 0;
307 }
308
309
310 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
311 {
312     spi_tms570_drv_t *tms570_drv =
313         UL_CONTAINEROF(ifc, spi_tms570_drv_t, spi_drv);
314
315     switch (ctrl) {
316     case SPI_CTRL_WAKE_RQ:
317         if (!(ifc->flags & SPI_IFC_ON))
318             return -1;
319         if (spi_rq_queue_is_empty(ifc))
320             return 0;
321
322         tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
323             // Enable TXINT (Causes an interrupt
324             // to be generated every time data is written to the shift
325             // register, so that the next word can be written to TXBUF.
326             // (=transmitter empty interrupt)
327             // Setting this bit will generate an interrupt if the
328             // TXINTFLG bit (SPI Flag Register (SPIFLG)[9]) is set to 1.;
329             // An interrupt request will be generated as soon as this
330             // bit is set to 1.
331         return 0;
332
333     default:
334         return -1;
335     }
336 }
337
338
339
340 /* -------------------------------------------------------------------------- */
341
342
343
344 void spi_tms570_isr(int spi_ifc, uint32_t flags)
345 {
346     spi_msg_head_t *msg;
347     spi_tms570_drv_t *spi_tms570_drv;
348     spi_tms570_drv = &spi_tms570_ifcs[spi_ifc];
349     spi_isr_lock_level_t saveif;
350     uint8_t val_to_wr;
351     uint32_t cs;
352     unsigned int rxcnt;
353     unsigned int txcnt;
354     unsigned int rq_len;
355     unsigned int rx_data;
356     int stop_fl;
357
358     if (flags & SPI_FLG_TXINT_m) {
359       do {
360         msg = spi_tms570_drv->spi_drv.msg_act;
361         if (!msg) { /* Is there any MSG being processed? */
362             /* If not, get one from a queue */
363             spi_isr_lock(saveif);
364             msg = spi_tms570_drv->spi_drv.msg_act =
365                 spi_rq_queue_first(&spi_tms570_drv->spi_drv);
366             spi_isr_unlock(saveif);
367
368             if (!msg) { /* Nothing to process */
369                 volatile unsigned int dummy_read;
370                 /* Disable TXEMPTY IRQ */
371                 spi_tms570_drv->spi->INT0 = 0x00;
372                 spi_tms570_drv->spi->FLG = 0x00;
373                 dummy_read = spi_tms570_drv->spi->BUF;
374                     // FIXME "INT |= " with disabled IRQ ??
375                 return;
376             }
377
378             spi_tms570_drv->txcnt = 0;
379             spi_tms570_drv->rxcnt = 0;
380             cs = spi_tms570_drv->spi_devs[msg->addr].cs;
381             spi_tms570_drv->transfer_ctrl =
382                     (cs & 0xff) << 16
383                     | (spi_tms570_drv->spi_devs[msg->addr].wdel & 0x1) << 26
384                     | (spi_tms570_drv->spi_devs[msg->addr].cshold & 0x1) << 28
385                     | (spi_tms570_drv->spi_devs[msg->addr].dfsel & 0x3) << 24;
386
387             /* GPIO CS -- setting the multiplexer */
388             if (cs > 0xff) {
389                 switch (cs & 0xFF00) {
390                 case SPI_CS_DMM0:
391                     dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
392                     dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
393                     break;
394                 case SPI_CS_DMM1:
395                     dmmREG->PC4 = (1 << DMM_DATA5); /* Set to H */
396                     dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
397                     break;
398                 case SPI_CS_DMM2:
399                     dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
400                     dmmREG->PC4 = (1 << DMM_DATA6); /* Set to H */
401                     break;
402                 }
403             }
404         }
405
406         rq_len = msg->rq_len;
407         rxcnt = spi_tms570_drv->rxcnt;
408         txcnt = spi_tms570_drv->txcnt;
409         /* RX/TX transfers */
410         do {
411             /* Receive all the incoming data */
412             while (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m) {
413                 rx_data = spi_tms570_drv->spi->BUF;
414
415                 if (msg->rx_buf && (rxcnt < rq_len)) {
416                     msg->rx_buf[rxcnt++] = rx_data & 0xFF;
417                     //FIXME how to make sure we got only 8 bits
418                 } else {
419                     rxcnt++;
420                 }
421             }
422
423             /* Send some data */
424             while (1) {
425                 /* Tx buffer full or nothing to send */
426                 stop_fl = ((txcnt >= rq_len) ||
427                         (!(spi_tms570_drv->spi->FLG & SPI_FLG_TXINT_m)));
428
429                 if (stop_fl)
430                     break;
431                 /* Make it possible to write "empty data"
432                    for "read transfers" */
433                 if (msg->tx_buf) {
434                     val_to_wr = msg->tx_buf[txcnt++];
435                 } else {
436                     val_to_wr = 0x00;
437                     txcnt++;
438                 }
439
440                 if (txcnt == rq_len) /* Disable CS for the last byte of the transfer */
441                     spi_tms570_drv->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
442
443                 spi_tms570_drv->spi->DAT1 =
444                     (uint32_t) (spi_tms570_drv->transfer_ctrl | val_to_wr);
445
446                 /* We just received something */
447                 if (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m)
448                     break;
449             }
450         } while (!stop_fl);
451         spi_tms570_drv->rxcnt = rxcnt;
452         spi_tms570_drv->txcnt = txcnt;
453
454         if ((rxcnt >= rq_len) ||
455             (!msg->rx_buf && (txcnt >= rq_len) &&
456              !(spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m))) { // FIXME
457
458             /* Sending of the message successfully finished */
459             spi_isr_lock(saveif);
460             spi_rq_queue_del_item(msg);
461             msg->flags |= SPI_MSG_FINISHED;
462             spi_tms570_drv->spi_drv.msg_act = NULL;
463             spi_isr_unlock(saveif);
464             if (msg->callback)
465                 msg->callback(&spi_tms570_drv->spi_drv,
466                     SPI_MSG_FINISHED, msg);
467
468             continue;
469         }
470         if (txcnt < rq_len) {
471             spi_tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
472         } else {
473             spi_tms570_drv->spi->INT0 = SPI_INT0_RXINTENA_m;
474         }
475
476       } while (1);
477     }
478 }
479
480 spi_drv_t *spi_find_drv(char *name, int number)
481 {
482     if (number < 1 || number > (sizeof(spi_tms570_ifcs)/sizeof(spi_tms570_ifcs[0])))
483         return NULL;
484
485     return  &spi_tms570_ifcs[number - 1].spi_drv;
486 }
487
488 #pragma INTERRUPT(spi2LowLevelInterrupt, IRQ)
489 void spi2LowLevelInterrupt(void)
490 {
491     uint32_t flags = spi_compat_REG2->FLG;// & (~spiREG2->LVL & 0x035F);
492     spi_tms570_isr(2 - 1, flags);
493 }
494
495 #pragma INTERRUPT(spi2HighLevelInterrupt, IRQ)
496 void spi2HighLevelInterrupt(void)
497 {
498     uint32_t flags = spi_compat_REG2->FLG;// & (~spiREG2->LVL & 0x035F);
499     spi_tms570_isr(2 - 1, flags);
500 }
501
502 #pragma INTERRUPT(spi4LowLevelInterrupt, IRQ)
503 void spi4LowLevelInterrupt(void)
504 {
505     uint32_t flags = spi_compat_REG4->FLG;// & (~spiREG4->LVL & 0x035F);
506     spi_tms570_isr(4 - 1, flags);
507 }
508
509 #pragma INTERRUPT(spi4HighLevelInterrupt, IRQ)
510 void spi4HighLevelInterrupt(void)
511 {
512     uint32_t flags = spi_compat_REG4->FLG;// & (~spiREG4->LVL & 0x035F);
513     spi_tms570_isr(4 - 1, flags);
514 }
515
516 #pragma INTERRUPT(mibspi1HighLevelInterrupt, IRQ)
517 void mibspi1HighLevelInterrupt(void)
518 {
519     uint32_t flags = mibspi_compat_REG1->FLG;// & (~mibspiREG1->LVL & 0x035F);
520     spi_tms570_isr(1 - 1, flags);
521 }
522
523 #pragma INTERRUPT(mibspi1LowLevelInterrupt, IRQ)
524 void mibspi1LowLevelInterrupt(void)
525 {
526     uint32_t flags = mibspi_compat_REG1->FLG;// & (~mibspiREG1->LVL & 0x035F);
527     spi_tms570_isr(1 - 1, flags);
528 }
529
530 #pragma INTERRUPT(mibspi3HighInterruptLevel, IRQ)
531 void mibspi3HighInterruptLevel(void)
532 {
533     uint32_t flags = mibspi_compat_REG3->FLG;// & (~mibspiREG3->LVL & 0x035F);
534     spi_tms570_isr(3 - 1, flags);
535 }
536
537 #pragma INTERRUPT(mibspi3LowLevelInterrupt, IRQ)
538 void mibspi3LowLevelInterrupt(void)
539 {
540     uint32_t flags = mibspi_compat_REG3->FLG;// & (~mibspiREG3->LVL & 0x035F);
541     spi_tms570_isr(3 - 1, flags);
542 }
543