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