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