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"
20 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
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];
27 /* Addresses of SPI devices (=chips) bound to particular interfaces */
28 enum spi_ifc1_devices {
29 SPIDEV_MC33972 = 0, SPIDEV_NCV7608_2x
31 enum spi_ifc2_devices {
34 enum spi_ifc3_devices {
35 SPIDEV_MCP4922_1 = 0, SPIDEV_MCP4922_2, SPIDEV_MCP4922_3
37 enum spi_ifc4_devices {
38 SPIDEV_L99H01 = 0, SPIDEV_TJA1082_1, SPIDEV_TJA1082_2
41 spi_dev_t spi_ifc1_devs[] = {
49 [SPIDEV_NCV7608_2x] = {
58 spi_dev_t spi_ifc2_devs[] = {
68 spi_dev_t spi_ifc3_devs[] = {
69 [SPIDEV_MCP4922_1] = {
76 [SPIDEV_MCP4922_2] = {
83 [SPIDEV_MCP4922_3] = {
92 spi_dev_t spi_ifc4_devs[] = {
94 .cs = SPI_CS_0 | SPI_CS_DMM0,
100 [SPIDEV_TJA1082_1] = {
101 .cs = SPI_CS_0 | SPI_CS_DMM1,
107 [SPIDEV_TJA1082_2] = {
108 .cs = SPI_CS_0 | SPI_CS_DMM2,
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
124 void spiInit(spiBASE_compat_t *spiREG)
126 /** bring SPI out of reset */
129 /** SPI master mode and clock configuration */
130 spiREG->GCR1 = (1 << 1) /* CLOKMOD */
133 /** SPI enable pin configuration */
134 spiREG->ENAHIGHZ = 0; /* ENABLE HIGHZ */
137 spiREG->DELAY = (0 << 24) /* C2TDELAY */
138 | (0 << 16) /* T2CDELAY */
139 | (0 << 8) /* T2EDELAY */
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 */
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 */
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 */
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 */
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 */
196 /** - clear any pending interrupts */
197 spiREG->FLG = 0xFFFFU;
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 */
209 /** initialize SPI Port */
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] */
222 | (0 << 10) /* SIMO */
223 | (0 << 11); /* SOMI */
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] */
236 | (1 << 10) /* SIMO */
237 | (0 << 11); /* SOMI */
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] */
250 | (0 << 10) /* SIMO */
251 | (0 << 11); /* SOMI */
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] */
264 | (1 << 10) /* SIMO */
265 | (1 << 11); /* SOMI */
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] */
278 | (0 << 10) /* SIMO */
279 | (0 << 11); /* SOMI */
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] */
292 | (1 << 10) /* SIMO */
293 | (1 << 11); /* SOMI */
295 /* Default CS logic levels */
296 spiREG->CSDEF = 0xFF;
298 /** Set MibSPI devices into compatibility mode --
299 "SPI" devices will hopefully ignore this */
300 spiREG->MIBSPIE = 0U;
302 /** - Finally start SPI */
306 static boolean_t spi_initialized = FALSE;
308 int spi_tms570_init(void)
310 if (spi_initialized == TRUE)
312 spi_initialized = TRUE;
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;
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;
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;
334 //dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
335 //dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
341 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
343 spi_tms570_drv_t *tms570_drv =
344 UL_CONTAINEROF(ifc, spi_tms570_drv_t, spi_drv);
347 case SPI_CTRL_WAKE_RQ:
348 if (!(ifc->flags & SPI_IFC_ON))
350 if (spi_rq_queue_is_empty(ifc))
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
371 /* -------------------------------------------------------------------------- */
375 void spi_tms570_isr(int spi_ifc, uint32_t flags)
378 spi_tms570_drv_t *spi_tms570_drv;
380 spi_tms570_drv = &spi_tms570_ifcs[spi_ifc];
381 spi_isr_lock_level_t saveif;
387 unsigned int rx_data;
390 if (flags & SPI_FLG_TXINT_m) {
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);
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 ??
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 =
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;
419 /* GPIO CS -- setting the multiplexer */
421 switch (cs & 0xFF00) {
423 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
424 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
427 dmmREG->PC4 = (1 << DMM_DATA5); /* Set to H */
428 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
431 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
432 dmmREG->PC4 = (1 << DMM_DATA6); /* Set to H */
438 rq_len = msg->rq_len;
439 rxcnt = spi_tms570_drv->rxcnt;
440 txcnt = spi_tms570_drv->txcnt;
441 /* RX/TX transfers */
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;
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
456 /* Tx buffer full or nothing to send */
457 stop_fl = ((txcnt >= rq_len) ||
458 (!(spi_tms570_drv->spi->FLG & SPI_FLG_TXINT_m)));
462 /* Make it possible to write "empty data"
463 for "read transfers" */
465 val_to_wr = msg->tx_buf[txcnt++];
471 if (txcnt == rq_len) /* Disable CS for the last byte of the transfer */
472 spi_tms570_drv->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
474 spi_tms570_drv->spi->DAT1 =
475 (uint32_t)(spi_tms570_drv->transfer_ctrl | val_to_wr);
477 /* We just received something */
478 if (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m)
482 spi_tms570_drv->rxcnt = rxcnt;
483 spi_tms570_drv->txcnt = txcnt;
485 if ((rxcnt >= rq_len) ||
486 (!msg->rx_buf && (txcnt >= rq_len) &&
487 !(spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m))) { // FIXME
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);
496 msg->callback(&spi_tms570_drv->spi_drv,
497 SPI_MSG_FINISHED, msg);
502 spi_tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
504 spi_tms570_drv->spi->INT0 = SPI_INT0_RXINTENA_m;
510 spi_drv_t *spi_find_drv(char *name, int number)
512 if (number < 1 || number > (sizeof(spi_tms570_ifcs)/sizeof(spi_tms570_ifcs[0])))
515 return &spi_tms570_ifcs[number - 1].spi_drv;
518 #pragma INTERRUPT(spi2LowLevelInterrupt, IRQ)
519 void spi2LowLevelInterrupt(void)
521 uint32_t flags = spi_compat_REG2->FLG; // & (~spiREG2->LVL & 0x035F);
523 spi_tms570_isr(2 - 1, flags);
526 #pragma INTERRUPT(spi2HighLevelInterrupt, IRQ)
527 void spi2HighLevelInterrupt(void)
529 uint32_t flags = spi_compat_REG2->FLG; // & (~spiREG2->LVL & 0x035F);
531 spi_tms570_isr(2 - 1, flags);
534 #pragma INTERRUPT(spi4LowLevelInterrupt, IRQ)
535 void spi4LowLevelInterrupt(void)
537 uint32_t flags = spi_compat_REG4->FLG; // & (~spiREG4->LVL & 0x035F);
539 spi_tms570_isr(4 - 1, flags);
542 #pragma INTERRUPT(spi4HighLevelInterrupt, IRQ)
543 void spi4HighLevelInterrupt(void)
545 uint32_t flags = spi_compat_REG4->FLG; // & (~spiREG4->LVL & 0x035F);
547 spi_tms570_isr(4 - 1, flags);
550 #pragma INTERRUPT(mibspi1HighLevelInterrupt, IRQ)
551 void mibspi1HighLevelInterrupt(void)
553 uint32_t flags = mibspi_compat_REG1->FLG; // & (~mibspiREG1->LVL & 0x035F);
555 spi_tms570_isr(1 - 1, flags);
558 #pragma INTERRUPT(mibspi1LowLevelInterrupt, IRQ)
559 void mibspi1LowLevelInterrupt(void)
561 uint32_t flags = mibspi_compat_REG1->FLG; // & (~mibspiREG1->LVL & 0x035F);
563 spi_tms570_isr(1 - 1, flags);
566 #pragma INTERRUPT(mibspi3HighInterruptLevel, IRQ)
567 void mibspi3HighInterruptLevel(void)
569 uint32_t flags = mibspi_compat_REG3->FLG; // & (~mibspiREG3->LVL & 0x035F);
571 spi_tms570_isr(3 - 1, flags);
574 #pragma INTERRUPT(mibspi3LowLevelInterrupt, IRQ)
575 void mibspi3LowLevelInterrupt(void)
577 uint32_t flags = mibspi_compat_REG3->FLG; // & (~mibspiREG3->LVL & 0x035F);
579 spi_tms570_isr(3 - 1, flags);