1 /* Copyright (C) 2012-2013, 2015 Czech Technical University in Prague
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.
10 * Code based on Halcogen generated source code
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"
21 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
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
31 void spiInit(spiBASE_compat_t *spiREG)
33 /** bring SPI out of reset */
36 /** SPI master mode and clock configuration */
37 spiREG->GCR1 = (1 << 1) /* CLOKMOD */
40 /** SPI enable pin configuration */
41 spiREG->ENAHIGHZ = 0; /* ENABLE HIGHZ */
44 spiREG->DELAY = (0 << 24) /* C2TDELAY */
45 | (0 << 16) /* T2CDELAY */
46 | (0 << 8) /* T2EDELAY */
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 */
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 */
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 */
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 */
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 */
103 /** - clear any pending interrupts */
104 spiREG->FLG = 0xFFFFU;
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 */
116 /** initialize SPI Port */
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] */
129 | (0 << 10) /* SIMO */
130 | (0 << 11); /* SOMI */
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] */
143 | (1 << 10) /* SIMO */
144 | (0 << 11); /* SOMI */
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] */
157 | (0 << 10) /* SIMO */
158 | (0 << 11); /* SOMI */
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] */
171 | (1 << 10) /* SIMO */
172 | (1 << 11); /* SOMI */
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] */
185 | (0 << 10) /* SIMO */
186 | (0 << 11); /* SOMI */
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] */
199 | (1 << 10) /* SIMO */
200 | (1 << 11); /* SOMI */
202 /* Default CS logic levels */
203 spiREG->CSDEF = 0xFF;
205 /** Set MibSPI devices into compatibility mode --
206 "SPI" devices will hopefully ignore this */
207 spiREG->MIBSPIE = 0U;
209 /** - Finally start SPI */
213 static boolean_t spi_initialized = FALSE;
215 int spi_tms570_init(spi_tms570_drv_t *ifcs, int count)
217 if (spi_initialized == TRUE)
219 spi_initialized = TRUE;
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;
230 //dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
231 //dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
237 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
239 spi_tms570_drv_t *tms570_drv =
240 UL_CONTAINEROF(ifc, spi_tms570_drv_t, spi_drv);
243 case SPI_CTRL_WAKE_RQ:
244 if (!(ifc->flags & SPI_IFC_ON))
246 if (spi_rq_queue_is_empty(ifc))
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
267 /* -------------------------------------------------------------------------- */
271 void spi_tms570_isr(int spi_ifc, uint32_t flags)
274 spi_tms570_drv_t *spi_tms570_drv = &spi_ifcs[spi_ifc];
275 spi_isr_lock_level_t saveif;
281 unsigned int rx_data;
284 if (flags & SPI_FLG_TXINT_m) {
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);
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 ??
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 =
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;
313 /* GPIO CS -- setting the multiplexer */
315 switch (cs & 0xFF00) {
317 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
318 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
321 dmmREG->PC4 = (1 << DMM_DATA5); /* Set to H */
322 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
325 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
326 dmmREG->PC4 = (1 << DMM_DATA6); /* Set to H */
332 rq_len = msg->rq_len;
333 rxcnt = spi_tms570_drv->rxcnt;
334 txcnt = spi_tms570_drv->txcnt;
335 /* RX/TX transfers */
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;
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
350 /* Tx buffer full or nothing to send */
351 stop_fl = ((txcnt >= rq_len) ||
352 (!(spi_tms570_drv->spi->FLG & SPI_FLG_TXINT_m)));
356 /* Make it possible to write "empty data"
357 for "read transfers" */
359 val_to_wr = msg->tx_buf[txcnt++];
365 if (txcnt == rq_len) /* Disable CS for the last byte of the transfer */
366 spi_tms570_drv->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
368 spi_tms570_drv->spi->DAT1 =
369 (uint32_t)(spi_tms570_drv->transfer_ctrl | val_to_wr);
371 /* We just received something */
372 if (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m)
376 spi_tms570_drv->rxcnt = rxcnt;
377 spi_tms570_drv->txcnt = txcnt;
379 if ((rxcnt >= rq_len) ||
380 (!msg->rx_buf && (txcnt >= rq_len) &&
381 !(spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m))) { // FIXME
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);
390 msg->callback(&spi_tms570_drv->spi_drv,
391 SPI_MSG_FINISHED, msg);
396 spi_tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
398 spi_tms570_drv->spi->INT0 = SPI_INT0_RXINTENA_m;
404 spi_drv_t *spi_find_drv(char *name, int number)
406 if (number < 1 || number > ARRAY_SIZE(spi_ifcs))
409 return &spi_ifcs[number - 1].spi_drv;
412 #pragma INTERRUPT(spi2LowLevelInterrupt, IRQ)
413 void spi2LowLevelInterrupt(void)
415 uint32_t flags = spi_compat_REG2->FLG; // & (~spiREG2->LVL & 0x035F);
417 spi_tms570_isr(2 - 1, flags);
420 #pragma INTERRUPT(spi2HighLevelInterrupt, IRQ)
421 void spi2HighLevelInterrupt(void)
423 uint32_t flags = spi_compat_REG2->FLG; // & (~spiREG2->LVL & 0x035F);
425 spi_tms570_isr(2 - 1, flags);
428 #pragma INTERRUPT(spi4LowLevelInterrupt, IRQ)
429 void spi4LowLevelInterrupt(void)
431 uint32_t flags = spi_compat_REG4->FLG; // & (~spiREG4->LVL & 0x035F);
433 spi_tms570_isr(4 - 1, flags);
436 #pragma INTERRUPT(spi4HighLevelInterrupt, IRQ)
437 void spi4HighLevelInterrupt(void)
439 uint32_t flags = spi_compat_REG4->FLG; // & (~spiREG4->LVL & 0x035F);
441 spi_tms570_isr(4 - 1, flags);
444 #pragma INTERRUPT(mibspi1HighLevelInterrupt, IRQ)
445 void mibspi1HighLevelInterrupt(void)
447 uint32_t flags = mibspi_compat_REG1->FLG; // & (~mibspiREG1->LVL & 0x035F);
449 spi_tms570_isr(1 - 1, flags);
452 #pragma INTERRUPT(mibspi1LowLevelInterrupt, IRQ)
453 void mibspi1LowLevelInterrupt(void)
455 uint32_t flags = mibspi_compat_REG1->FLG; // & (~mibspiREG1->LVL & 0x035F);
457 spi_tms570_isr(1 - 1, flags);
460 #pragma INTERRUPT(mibspi3HighInterruptLevel, IRQ)
461 void mibspi3HighInterruptLevel(void)
463 uint32_t flags = mibspi_compat_REG3->FLG; // & (~mibspiREG3->LVL & 0x035F);
465 spi_tms570_isr(3 - 1, flags);
468 #pragma INTERRUPT(mibspi3LowLevelInterrupt, IRQ)
469 void mibspi3LowLevelInterrupt(void)
471 uint32_t flags = mibspi_compat_REG3->FLG; // & (~mibspiREG3->LVL & 0x035F);
473 spi_tms570_isr(3 - 1, flags);