1 /* Code based on Halcogen generated source code */
3 //#include "spi_tms570.h"
5 //#include "sys_common.h"
6 //#include "ti_drv_dmm.h"
9 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
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];
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 };
22 spi_dev_t spi_ifc1_devs[] = {
29 [SPIDEV_NCV7608_2x] = {
37 spi_dev_t spi_ifc2_devs[] = {
46 spi_dev_t spi_ifc3_devs[] = {
47 [SPIDEV_MCP4922_1] = {
53 [SPIDEV_MCP4922_2] = {
59 [SPIDEV_MCP4922_3] = {
67 spi_dev_t spi_ifc4_devs[] = {
69 .cs = SPI_CS_0 | SPI_CS_DMM0,
74 [SPIDEV_TJA1082_1] = {
75 .cs = SPI_CS_0 | SPI_CS_DMM1,
80 [SPIDEV_TJA1082_2] = {
81 .cs = SPI_CS_0 | SPI_CS_DMM2,
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
96 void spiInit(spiBASE_compat_t *spiREG)
98 /** bring SPI out of reset */
101 /** SPI master mode and clock configuration */
102 spiREG->GCR1 = (1 << 1) /* CLOKMOD */
105 /** SPI enable pin configuration */
106 spiREG->ENAHIGHZ = 0; /* ENABLE HIGHZ */
109 spiREG->DELAY = (0 << 24) /* C2TDELAY */
110 | (0 << 16) /* T2CDELAY */
111 | (0 << 8) /* T2EDELAY */
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 */
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 */
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 */
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 */
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 */
168 /** - clear any pending interrupts */
169 spiREG->FLG = 0xFFFFU;
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 */
181 /** initialize SPI Port */
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] */
194 | (0 << 10) /* SIMO */
195 | (0 << 11); /* SOMI */
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] */
208 | (1 << 10) /* SIMO */
209 | (0 << 11); /* SOMI */
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] */
222 | (0 << 10) /* SIMO */
223 | (0 << 11); /* SOMI */
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] */
236 | (1 << 10) /* SIMO */
237 | (1 << 11); /* SOMI */
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] */
250 | (0 << 10) /* SIMO */
251 | (0 << 11); /* SOMI */
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] */
264 | (1 << 10) /* SIMO */
265 | (1 << 11); /* SOMI */
267 /* Default CS logic levels */
268 spiREG->CSDEF = 0xFF;
270 /** Set MibSPI devices into compatibility mode --
271 "SPI" devices will hopefully ignore this */
272 spiREG->MIBSPIE = 0U;
274 /** - Finally start SPI */
279 int spi_tms570_init(void)
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;
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;
294 for (i = 0; i <= 3; i++)
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;
303 //dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
304 //dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
310 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
312 spi_tms570_drv_t *tms570_drv =
313 UL_CONTAINEROF(ifc, spi_tms570_drv_t, spi_drv);
316 case SPI_CTRL_WAKE_RQ:
317 if (!(ifc->flags & SPI_IFC_ON))
319 if (spi_rq_queue_is_empty(ifc))
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
340 /* -------------------------------------------------------------------------- */
344 void spi_tms570_isr(int spi_ifc, uint32_t flags)
347 spi_tms570_drv_t *spi_tms570_drv;
348 spi_tms570_drv = &spi_tms570_ifcs[spi_ifc];
349 spi_isr_lock_level_t saveif;
355 unsigned int rx_data;
358 if (flags & SPI_FLG_TXINT_m) {
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);
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 ??
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 =
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;
387 /* GPIO CS -- setting the multiplexer */
389 switch (cs & 0xFF00) {
391 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
392 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
395 dmmREG->PC4 = (1 << DMM_DATA5); /* Set to H */
396 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
399 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
400 dmmREG->PC4 = (1 << DMM_DATA6); /* Set to H */
406 rq_len = msg->rq_len;
407 rxcnt = spi_tms570_drv->rxcnt;
408 txcnt = spi_tms570_drv->txcnt;
409 /* RX/TX transfers */
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;
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
425 /* Tx buffer full or nothing to send */
426 stop_fl = ((txcnt >= rq_len) ||
427 (!(spi_tms570_drv->spi->FLG & SPI_FLG_TXINT_m)));
431 /* Make it possible to write "empty data"
432 for "read transfers" */
434 val_to_wr = msg->tx_buf[txcnt++];
440 if (txcnt == rq_len) /* Disable CS for the last byte of the transfer */
441 spi_tms570_drv->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
443 spi_tms570_drv->spi->DAT1 =
444 (uint32_t) (spi_tms570_drv->transfer_ctrl | val_to_wr);
446 /* We just received something */
447 if (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m)
451 spi_tms570_drv->rxcnt = rxcnt;
452 spi_tms570_drv->txcnt = txcnt;
454 if ((rxcnt >= rq_len) ||
455 (!msg->rx_buf && (txcnt >= rq_len) &&
456 !(spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m))) { // FIXME
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);
465 msg->callback(&spi_tms570_drv->spi_drv,
466 SPI_MSG_FINISHED, msg);
470 if (txcnt < rq_len) {
471 spi_tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
473 spi_tms570_drv->spi->INT0 = SPI_INT0_RXINTENA_m;
480 spi_drv_t *spi_find_drv(char *name, int number)
482 if (number < 1 || number > (sizeof(spi_tms570_ifcs)/sizeof(spi_tms570_ifcs[0])))
485 return &spi_tms570_ifcs[number - 1].spi_drv;
488 #pragma INTERRUPT(spi2LowLevelInterrupt, IRQ)
489 void spi2LowLevelInterrupt(void)
491 uint32_t flags = spi_compat_REG2->FLG;// & (~spiREG2->LVL & 0x035F);
492 spi_tms570_isr(2 - 1, flags);
495 #pragma INTERRUPT(spi2HighLevelInterrupt, IRQ)
496 void spi2HighLevelInterrupt(void)
498 uint32_t flags = spi_compat_REG2->FLG;// & (~spiREG2->LVL & 0x035F);
499 spi_tms570_isr(2 - 1, flags);
502 #pragma INTERRUPT(spi4LowLevelInterrupt, IRQ)
503 void spi4LowLevelInterrupt(void)
505 uint32_t flags = spi_compat_REG4->FLG;// & (~spiREG4->LVL & 0x035F);
506 spi_tms570_isr(4 - 1, flags);
509 #pragma INTERRUPT(spi4HighLevelInterrupt, IRQ)
510 void spi4HighLevelInterrupt(void)
512 uint32_t flags = spi_compat_REG4->FLG;// & (~spiREG4->LVL & 0x035F);
513 spi_tms570_isr(4 - 1, flags);
516 #pragma INTERRUPT(mibspi1HighLevelInterrupt, IRQ)
517 void mibspi1HighLevelInterrupt(void)
519 uint32_t flags = mibspi_compat_REG1->FLG;// & (~mibspiREG1->LVL & 0x035F);
520 spi_tms570_isr(1 - 1, flags);
523 #pragma INTERRUPT(mibspi1LowLevelInterrupt, IRQ)
524 void mibspi1LowLevelInterrupt(void)
526 uint32_t flags = mibspi_compat_REG1->FLG;// & (~mibspiREG1->LVL & 0x035F);
527 spi_tms570_isr(1 - 1, flags);
530 #pragma INTERRUPT(mibspi3HighInterruptLevel, IRQ)
531 void mibspi3HighInterruptLevel(void)
533 uint32_t flags = mibspi_compat_REG3->FLG;// & (~mibspiREG3->LVL & 0x035F);
534 spi_tms570_isr(3 - 1, flags);
537 #pragma INTERRUPT(mibspi3LowLevelInterrupt, IRQ)
538 void mibspi3LowLevelInterrupt(void)
540 uint32_t flags = mibspi_compat_REG3->FLG;// & (~mibspiREG3->LVL & 0x035F);
541 spi_tms570_isr(3 - 1, flags);