1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <string.h>
19
20 #include <gpio.h>
21 #include <spi.h>
22 #include <spi_priv.h>
23 #include <util.h>
24 #include <atomicBitset.h>
25 #include <atomic.h>
26 #include <platform.h>
27
28 #include <plat/cmsis.h>
29 #include <plat/dma.h>
30 #include <plat/gpio.h>
31 #include <plat/pwr.h>
32 #include <plat/exti.h>
33 #include <plat/syscfg.h>
34 #include <plat/spi.h>
35 #include <plat/plat.h>
36
37 #define SPI_CR1_CPHA (1 << 0)
38 #define SPI_CR1_CPOL (1 << 1)
39 #define SPI_CR1_MSTR (1 << 2)
40
41 #define SPI_CR1_BR(x) ((LOG2_CEIL(x) - 1) << 3)
42 #define SPI_CR1_BR_MIN 2
43 #define SPI_CR1_BR_MAX 256
44 #define SPI_CR1_BR_MASK (0x7 << 3)
45
46 #define SPI_CR1_SPE (1 << 6)
47 #define SPI_CR1_LSBFIRST (1 << 7)
48 #define SPI_CR1_SSI (1 << 8)
49 #define SPI_CR1_SSM (1 << 9)
50 #define SPI_CR1_RXONLY (1 << 10)
51 #define SPI_CR1_DFF (1 << 11)
52 #define SPI_CR1_BIDIOE (1 << 14)
53 #define SPI_CR1_BIDIMODE (1 << 15)
54
55 #define SPI_CR2_TXEIE (1 << 7)
56 #define SPI_CR2_RXNEIE (1 << 6)
57 #define SPI_CR2_ERRIE (1 << 5)
58 #define SPI_CR2_TXDMAEN (1 << 1)
59 #define SPI_CR2_RXDMAEN (1 << 0)
60 #define SPI_CR2_INT_MASK (SPI_CR2_TXEIE | SPI_CR2_RXNEIE | SPI_CR2_ERRIE)
61
62 #define SPI_CR2_SSOE (1 << 2)
63
64 #define SPI_SR_RXNE (1 << 0)
65 #define SPI_SR_TXE (1 << 1)
66 #define SPI_SR_BSY (1 << 7)
67
68 struct StmSpi {
69 volatile uint32_t CR1;
70 volatile uint32_t CR2;
71 volatile uint32_t SR;
72 volatile uint32_t DR;
73 volatile uint32_t CRCPR;
74 volatile uint32_t RXCRCR;
75 volatile uint32_t TXCRCR;
76 volatile uint32_t I2SCFGR;
77 volatile uint32_t I2SPR;
78 };
79
80 struct StmSpiState {
81 uint8_t bitsPerWord;
82 uint8_t xferEnable;
83
84 uint16_t rxWord;
85 uint16_t txWord;
86
87 bool rxDone;
88 bool txDone;
89
90 struct ChainedIsr isrNss;
91
92 bool nssChange;
93 };
94
95 struct StmSpiCfg {
96 struct StmSpi *regs;
97
98 uint32_t clockBus;
99 uint32_t clockUnit;
100
101 IRQn_Type irq;
102
103 uint8_t dmaBus;
104 };
105
106 struct StmSpiDev {
107 struct SpiDevice *base;
108 const struct StmSpiCfg *cfg;
109 const struct StmSpiBoardCfg *board;
110 struct StmSpiState state;
111
112 struct Gpio *miso;
113 struct Gpio *mosi;
114 struct Gpio *sck;
115 struct Gpio *nss;
116 };
117
stmSpiGpioInit(uint32_t gpioNum,enum StmGpioSpeed speed,enum StmGpioAltFunc func)118 static inline struct Gpio *stmSpiGpioInit(uint32_t gpioNum, enum StmGpioSpeed speed, enum StmGpioAltFunc func)
119 {
120 struct Gpio *gpio = gpioRequest(gpioNum);
121
122 if (gpio)
123 gpioConfigAlt(gpio, speed, GPIO_PULL_NONE, GPIO_OUT_PUSH_PULL, func);
124
125 return gpio;
126 }
127
stmSpiDataPullMode(struct StmSpiDev * pdev,enum StmGpioSpeed dataSpeed,enum GpioPullMode dataPull)128 static inline void stmSpiDataPullMode(struct StmSpiDev *pdev, enum StmGpioSpeed dataSpeed, enum GpioPullMode dataPull)
129 {
130 gpioConfigAlt(pdev->miso, dataSpeed, dataPull, GPIO_OUT_PUSH_PULL, pdev->board->gpioFunc);
131 gpioConfigAlt(pdev->mosi, dataSpeed, dataPull, GPIO_OUT_PUSH_PULL, pdev->board->gpioFunc);
132 }
133
stmSpiSckPullMode(struct StmSpiDev * pdev,enum StmGpioSpeed sckSpeed,enum GpioPullMode sckPull)134 static inline void stmSpiSckPullMode(struct StmSpiDev *pdev, enum StmGpioSpeed sckSpeed, enum GpioPullMode sckPull)
135 {
136 gpioConfigAlt(pdev->sck, sckSpeed, sckPull, GPIO_OUT_PUSH_PULL, pdev->board->gpioFunc);
137 }
138
stmSpiStartDma(struct StmSpiDev * pdev,const struct StmSpiDmaCfg * dmaCfg,const void * buf,uint8_t bitsPerWord,bool minc,size_t size,DmaCallbackF callback,bool rx)139 static inline void stmSpiStartDma(struct StmSpiDev *pdev,
140 const struct StmSpiDmaCfg *dmaCfg, const void *buf, uint8_t bitsPerWord,
141 bool minc, size_t size, DmaCallbackF callback, bool rx)
142 {
143 struct StmSpi *regs = pdev->cfg->regs;
144 struct dmaMode mode;
145
146 memset(&mode, 0, sizeof(mode));
147
148 if (bitsPerWord == 8) {
149 mode.psize = DMA_SIZE_8_BITS;
150 mode.msize = DMA_SIZE_8_BITS;
151 } else {
152 mode.psize = DMA_SIZE_16_BITS;
153 mode.msize = DMA_SIZE_16_BITS;
154 }
155 mode.priority = DMA_PRIORITY_HIGH;
156 mode.direction = rx ? DMA_DIRECTION_PERIPH_TO_MEM :
157 DMA_DIRECTION_MEM_TO_PERIPH;
158 mode.periphAddr = (uintptr_t)®s->DR;
159 mode.minc = minc;
160 mode.channel = dmaCfg->channel;
161
162 dmaStart(pdev->cfg->dmaBus, dmaCfg->stream, buf, size, &mode, callback,
163 pdev);
164 }
165
stmSpiEnable(struct StmSpiDev * pdev,const struct SpiMode * mode,bool master)166 static inline int stmSpiEnable(struct StmSpiDev *pdev,
167 const struct SpiMode *mode, bool master)
168 {
169 struct StmSpi *regs = pdev->cfg->regs;
170 struct StmSpiState *state = &pdev->state;
171
172 if (mode->bitsPerWord != 8 &&
173 mode->bitsPerWord != 16)
174 return -EINVAL;
175
176 unsigned int div;
177 if (master) {
178 if (!mode->speed)
179 return -EINVAL;
180
181 uint32_t pclk = pwrGetBusSpeed(pdev->cfg->clockBus);
182 div = pclk / mode->speed;
183 if (div > SPI_CR1_BR_MAX)
184 return -EINVAL;
185 else if (div < SPI_CR1_BR_MIN)
186 div = SPI_CR1_BR_MIN;
187 }
188
189 atomicWriteByte(&state->xferEnable, false);
190
191 state->txWord = mode->txWord;
192 state->bitsPerWord = mode->bitsPerWord;
193
194 pwrUnitClock(pdev->cfg->clockBus, pdev->cfg->clockUnit, true);
195
196 if (master) {
197 regs->CR1 &= ~SPI_CR1_BR_MASK;
198 regs->CR1 |= SPI_CR1_BR(div);
199 }
200
201 if (mode->cpol == SPI_CPOL_IDLE_LO)
202 regs->CR1 &= ~SPI_CR1_CPOL;
203 else
204 regs->CR1 |= SPI_CR1_CPOL;
205
206 if (mode->cpha == SPI_CPHA_LEADING_EDGE)
207 regs->CR1 &= ~SPI_CR1_CPHA;
208 else
209 regs->CR1 |= SPI_CR1_CPHA;
210
211 if (mode->bitsPerWord == 8)
212 regs->CR1 &= ~SPI_CR1_DFF;
213 else
214 regs->CR1 |= SPI_CR1_DFF;
215
216 if (mode->format == SPI_FORMAT_MSB_FIRST)
217 regs->CR1 &= ~SPI_CR1_LSBFIRST;
218 else
219 regs->CR1 |= SPI_CR1_LSBFIRST;
220
221 if (master)
222 regs->CR1 |= SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_MSTR;
223 else
224 regs->CR1 &= ~(SPI_CR1_SSM | SPI_CR1_MSTR);
225
226 return 0;
227 }
228
stmSpiMasterStartSync(struct SpiDevice * dev,spi_cs_t cs,const struct SpiMode * mode)229 static int stmSpiMasterStartSync(struct SpiDevice *dev, spi_cs_t cs,
230 const struct SpiMode *mode)
231 {
232 struct StmSpiDev *pdev = dev->pdata;
233
234 int err = stmSpiEnable(pdev, mode, true);
235 if (err < 0)
236 return err;
237
238 stmSpiDataPullMode(pdev, pdev->board->gpioSpeed, pdev->board->gpioPull);
239 stmSpiSckPullMode(pdev, pdev->board->gpioSpeed, mode->cpol ? GPIO_PULL_UP : GPIO_PULL_DOWN);
240
241 if (!pdev->nss)
242 pdev->nss = gpioRequest(cs);
243 if (!pdev->nss)
244 return -ENODEV;
245 gpioConfigOutput(pdev->nss, pdev->board->gpioSpeed, pdev->board->gpioPull, GPIO_OUT_PUSH_PULL, 1);
246
247 return 0;
248 }
249
stmSpiSlaveStartSync(struct SpiDevice * dev,const struct SpiMode * mode)250 static int stmSpiSlaveStartSync(struct SpiDevice *dev,
251 const struct SpiMode *mode)
252 {
253 struct StmSpiDev *pdev = dev->pdata;
254
255 stmSpiDataPullMode(pdev, pdev->board->gpioSpeed, GPIO_PULL_NONE);
256 stmSpiSckPullMode(pdev, pdev->board->gpioSpeed, GPIO_PULL_NONE);
257
258 if (!pdev->nss)
259 pdev->nss = stmSpiGpioInit(pdev->board->gpioNss, pdev->board->gpioSpeed, pdev->board->gpioFunc);
260 if (!pdev->nss)
261 return -ENODEV;
262
263 return stmSpiEnable(pdev, mode, false);
264 }
265
stmSpiIsMaster(struct StmSpiDev * pdev)266 static inline bool stmSpiIsMaster(struct StmSpiDev *pdev)
267 {
268 struct StmSpi *regs = pdev->cfg->regs;
269 return !!(regs->CR1 & SPI_CR1_MSTR);
270 }
271
stmSpiDone(struct StmSpiDev * pdev,int err)272 static void stmSpiDone(struct StmSpiDev *pdev, int err)
273 {
274 struct StmSpi *regs = pdev->cfg->regs;
275 struct StmSpiState *state = &pdev->state;
276
277 if (pdev->board->sleepDev >= 0)
278 platReleaseDevInSleepMode(pdev->board->sleepDev);
279
280 while (regs->SR & SPI_SR_BSY)
281 ;
282
283 if (stmSpiIsMaster(pdev)) {
284 if (state->nssChange && pdev->nss)
285 gpioSet(pdev->nss, 1);
286 spiMasterRxTxDone(pdev->base, err);
287 } else {
288 regs->CR2 = SPI_CR2_TXEIE;
289 spiSlaveRxTxDone(pdev->base, err);
290 }
291 }
292
stmSpiRxDone(void * cookie,uint16_t bytesLeft,int err)293 static void stmSpiRxDone(void *cookie, uint16_t bytesLeft, int err)
294 {
295 struct StmSpiDev *pdev = cookie;
296 struct StmSpi *regs = pdev->cfg->regs;
297 struct StmSpiState *state = &pdev->state;
298
299 regs->CR2 &= ~SPI_CR2_RXDMAEN;
300 state->rxDone = true;
301
302 if (state->txDone) {
303 atomicWriteByte(&state->xferEnable, false);
304 stmSpiDone(pdev, err);
305 }
306 }
307
stmSpiTxDone(void * cookie,uint16_t bytesLeft,int err)308 static void stmSpiTxDone(void *cookie, uint16_t bytesLeft, int err)
309 {
310 struct StmSpiDev *pdev = cookie;
311 struct StmSpi *regs = pdev->cfg->regs;
312 struct StmSpiState *state = &pdev->state;
313
314 regs->CR2 &= ~SPI_CR2_TXDMAEN;
315 state->txDone = true;
316
317 if (state->rxDone) {
318 atomicWriteByte(&state->xferEnable, false);
319 stmSpiDone(pdev, err);
320 }
321 }
322
stmSpiRxTx(struct SpiDevice * dev,void * rxBuf,const void * txBuf,size_t size,const struct SpiMode * mode)323 static int stmSpiRxTx(struct SpiDevice *dev, void *rxBuf, const void *txBuf,
324 size_t size, const struct SpiMode *mode)
325 {
326 struct StmSpiDev *pdev = dev->pdata;
327 struct StmSpi *regs = pdev->cfg->regs;
328 struct StmSpiState *state = &pdev->state;
329 bool rxMinc = true, txMinc = true;
330 uint32_t cr2 = SPI_CR2_TXDMAEN;
331
332 if (atomicXchgByte(&state->xferEnable, true) == true)
333 return -EBUSY;
334
335 if (stmSpiIsMaster(pdev) && pdev->nss)
336 gpioSet(pdev->nss, 0);
337
338 state->rxDone = false;
339 state->txDone = false;
340 state->nssChange = mode->nssChange;
341
342 /* In master mode, if RX is ignored at any point, then turning it on
343 * later may cause the SPI/DMA controllers to "receive" a stale byte
344 * sitting in a FIFO somewhere (even when their respective registers say
345 * their FIFOs are empty, and even if the SPI FIFO is explicitly cleared).
346 * Work around this by DMAing bytes we don't care about into a throwaway
347 * 1-word buffer.
348 *
349 * In slave mode, this specific WAR sometimes causes bigger problems
350 * (the first byte TXed is sometimes dropped or corrupted). Slave mode
351 * has its own WARs below.
352 */
353 if (!rxBuf && stmSpiIsMaster(pdev)) {
354 rxBuf = &state->rxWord;
355 rxMinc = false;
356 }
357
358 if (rxBuf) {
359 stmSpiStartDma(pdev, &pdev->board->dmaRx, rxBuf, mode->bitsPerWord,
360 rxMinc, size, stmSpiRxDone, true);
361 cr2 |= SPI_CR2_RXDMAEN;
362 } else {
363 state->rxDone = true;
364 }
365
366 if (!txBuf) {
367 txBuf = &state->txWord;
368 txMinc = false;
369 }
370 stmSpiStartDma(pdev, &pdev->board->dmaTx, txBuf, mode->bitsPerWord, txMinc,
371 size, stmSpiTxDone, false);
372
373 /* Ensure the TXE and RXNE bits are cleared; otherwise the DMA controller
374 * may "receive" the byte sitting in the SPI controller's FIFO right now,
375 * or drop/corrupt the first TX byte. Timing is crucial here, so do it
376 * right before enabling DMA.
377 */
378 if (!stmSpiIsMaster(pdev)) {
379 regs->CR2 &= ~SPI_CR2_TXEIE;
380 NVIC_ClearPendingIRQ(pdev->cfg->irq);
381
382 if (regs->SR & SPI_SR_RXNE)
383 (void)regs->DR;
384
385 if (regs->SR & SPI_SR_TXE)
386 regs->DR = mode->txWord;
387 }
388
389 if (pdev->board->sleepDev >= 0)
390 platRequestDevInSleepMode(pdev->board->sleepDev, 12);
391
392 regs->CR2 = cr2;
393 regs->CR1 |= SPI_CR1_SPE;
394
395
396 return 0;
397 }
398
stmSpiSlaveIdle(struct SpiDevice * dev,const struct SpiMode * mode)399 static int stmSpiSlaveIdle(struct SpiDevice *dev, const struct SpiMode *mode)
400 {
401 struct StmSpiDev *pdev = dev->pdata;
402 struct StmSpi *regs = pdev->cfg->regs;
403 struct StmSpiState *state = &pdev->state;
404
405 if (atomicXchgByte(&state->xferEnable, true) == true)
406 return -EBUSY;
407
408 regs->CR2 = SPI_CR2_TXEIE;
409 regs->CR1 |= SPI_CR1_SPE;
410
411 atomicXchgByte(&state->xferEnable, false);
412 return 0;
413 }
414
stmSpiDisable(struct SpiDevice * dev,bool master)415 static inline void stmSpiDisable(struct SpiDevice *dev, bool master)
416 {
417 struct StmSpiDev *pdev = dev->pdata;
418 struct StmSpi *regs = pdev->cfg->regs;
419
420 while (regs->SR & SPI_SR_BSY)
421 ;
422
423 if (master) {
424 stmSpiSckPullMode(pdev, pdev->board->gpioSpeed, pdev->board->gpioPull);
425 }
426
427 regs->CR2 &= ~(SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN | SPI_CR2_TXEIE);
428 regs->CR1 &= ~SPI_CR1_SPE;
429 pwrUnitClock(pdev->cfg->clockBus, pdev->cfg->clockUnit, false);
430 }
431
stmSpiMasterStopSync(struct SpiDevice * dev)432 static int stmSpiMasterStopSync(struct SpiDevice *dev)
433 {
434 struct StmSpiDev *pdev = dev->pdata;
435
436 if (pdev->nss) {
437 gpioSet(pdev->nss, 1);
438 gpioRelease(pdev->nss);
439 }
440
441 stmSpiDisable(dev, true);
442 pdev->nss = NULL;
443 return 0;
444 }
445
stmSpiSlaveStopSync(struct SpiDevice * dev)446 static int stmSpiSlaveStopSync(struct SpiDevice *dev)
447 {
448 struct StmSpiDev *pdev = dev->pdata;
449
450 if (pdev->nss)
451 gpioRelease(pdev->nss);
452
453 stmSpiDisable(dev, false);
454 pdev->nss = NULL;
455 return 0;
456 }
457
stmSpiExtiIsr(struct ChainedIsr * isr)458 static bool stmSpiExtiIsr(struct ChainedIsr *isr)
459 {
460 struct StmSpiState *state = container_of(isr, struct StmSpiState, isrNss);
461 struct StmSpiDev *pdev = container_of(state, struct StmSpiDev, state);
462
463 if (pdev->nss && !extiIsPendingGpio(pdev->nss))
464 return false;
465
466 spiSlaveCsInactive(pdev->base);
467 if (pdev->nss)
468 extiClearPendingGpio(pdev->nss);
469 return true;
470 }
471
stmSpiSlaveSetCsInterrupt(struct SpiDevice * dev,bool enabled)472 static void stmSpiSlaveSetCsInterrupt(struct SpiDevice *dev, bool enabled)
473 {
474 struct StmSpiDev *pdev = dev->pdata;
475 struct ChainedIsr *isr = &pdev->state.isrNss;
476
477 if (enabled) {
478 isr->func = stmSpiExtiIsr;
479
480 if (pdev->nss) {
481 syscfgSetExtiPort(pdev->nss);
482 extiEnableIntGpio(pdev->nss, EXTI_TRIGGER_RISING);
483 }
484 extiChainIsr(pdev->board->irqNss, isr);
485 } else {
486 extiUnchainIsr(pdev->board->irqNss, isr);
487 if (pdev->nss)
488 extiDisableIntGpio(pdev->nss);
489 }
490 }
491
stmSpiSlaveCsIsActive(struct SpiDevice * dev)492 static bool stmSpiSlaveCsIsActive(struct SpiDevice *dev)
493 {
494 struct StmSpiDev *pdev = dev->pdata;
495 return pdev->nss && !gpioGet(pdev->nss);
496 }
497
stmSpiTxe(struct StmSpiDev * pdev)498 static inline void stmSpiTxe(struct StmSpiDev *pdev)
499 {
500 struct StmSpi *regs = pdev->cfg->regs;
501
502 /**
503 * n.b.: if nothing handles the TXE interrupt in slave mode, the SPI
504 * controller will just keep reading the existing value from DR anytime it
505 * needs data
506 */
507 regs->DR = pdev->state.txWord;
508 regs->CR2 &= ~SPI_CR2_TXEIE;
509 }
510
stmSpiIsr(struct StmSpiDev * pdev)511 static void stmSpiIsr(struct StmSpiDev *pdev)
512 {
513 struct StmSpi *regs = pdev->cfg->regs;
514
515 if (regs->SR & SPI_SR_TXE) {
516 stmSpiTxe(pdev);
517 }
518
519 /* TODO: error conditions */
520 }
521
stmSpiRelease(struct SpiDevice * dev)522 static int stmSpiRelease(struct SpiDevice *dev)
523 {
524 struct StmSpiDev *pdev = dev->pdata;
525
526 NVIC_DisableIRQ(pdev->cfg->irq);
527
528 pdev->base = NULL;
529 return 0;
530 }
531
532 #define DECLARE_IRQ_HANDLER(_n) \
533 void SPI##_n##_IRQHandler(); \
534 void SPI##_n##_IRQHandler() \
535 { \
536 stmSpiIsr(&mStmSpiDevs[_n - 1]); \
537 }
538
539 const struct SpiDevice_ops mStmSpiOps = {
540 .masterStartSync = stmSpiMasterStartSync,
541 .masterRxTx = stmSpiRxTx,
542 .masterStopSync = stmSpiMasterStopSync,
543
544 .slaveStartSync = stmSpiSlaveStartSync,
545 .slaveIdle = stmSpiSlaveIdle,
546 .slaveRxTx = stmSpiRxTx,
547 .slaveStopSync = stmSpiSlaveStopSync,
548
549 .slaveSetCsInterrupt = stmSpiSlaveSetCsInterrupt,
550 .slaveCsIsActive = stmSpiSlaveCsIsActive,
551
552 .release = stmSpiRelease,
553 };
554
555 static const struct StmSpiCfg mStmSpiCfgs[] = {
556 [0] = {
557 .regs = (struct StmSpi *)SPI1_BASE,
558
559 .clockBus = PERIPH_BUS_APB2,
560 .clockUnit = PERIPH_APB2_SPI1,
561
562 .irq = SPI1_IRQn,
563
564 .dmaBus = SPI1_DMA_BUS,
565 },
566 [1] = {
567 .regs = (struct StmSpi *)SPI2_BASE,
568
569 .clockBus = PERIPH_BUS_APB1,
570 .clockUnit = PERIPH_APB1_SPI2,
571
572 .irq = SPI2_IRQn,
573
574 .dmaBus = SPI2_DMA_BUS,
575 },
576 [2] = {
577 .regs = (struct StmSpi *)SPI3_BASE,
578
579 .clockBus = PERIPH_BUS_APB1,
580 .clockUnit = PERIPH_APB1_SPI3,
581
582 .irq = SPI3_IRQn,
583
584 .dmaBus = SPI3_DMA_BUS,
585 },
586 };
587
588 static struct StmSpiDev mStmSpiDevs[ARRAY_SIZE(mStmSpiCfgs)];
589 DECLARE_IRQ_HANDLER(1)
590 DECLARE_IRQ_HANDLER(2)
591 DECLARE_IRQ_HANDLER(3)
592
stmSpiInit(struct StmSpiDev * pdev,const struct StmSpiCfg * cfg,const struct StmSpiBoardCfg * board,struct SpiDevice * dev)593 static void stmSpiInit(struct StmSpiDev *pdev, const struct StmSpiCfg *cfg,
594 const struct StmSpiBoardCfg *board, struct SpiDevice *dev)
595 {
596 pdev->miso = stmSpiGpioInit(board->gpioMiso, board->gpioSpeed, board->gpioFunc);
597 pdev->mosi = stmSpiGpioInit(board->gpioMosi, board->gpioSpeed, board->gpioFunc);
598 pdev->sck = stmSpiGpioInit(board->gpioSclk, board->gpioSpeed, board->gpioFunc);
599
600 NVIC_EnableIRQ(cfg->irq);
601
602 pdev->base = dev;
603 pdev->cfg = cfg;
604 pdev->board = board;
605 }
606
spiRequest(struct SpiDevice * dev,uint8_t busId)607 int spiRequest(struct SpiDevice *dev, uint8_t busId)
608 {
609 if (busId >= ARRAY_SIZE(mStmSpiDevs))
610 return -ENODEV;
611
612 const struct StmSpiBoardCfg *board = boardStmSpiCfg(busId);
613 if (!board)
614 return -ENODEV;
615
616 struct StmSpiDev *pdev = &mStmSpiDevs[busId];
617 const struct StmSpiCfg *cfg = &mStmSpiCfgs[busId];
618 if (!pdev->base)
619 stmSpiInit(pdev, cfg, board, dev);
620
621 memset(&pdev->state, 0, sizeof(pdev->state));
622 dev->ops = &mStmSpiOps;
623 dev->pdata = pdev;
624 return 0;
625 }
626
spiRxIrq(uint8_t busId)627 const enum IRQn spiRxIrq(uint8_t busId)
628 {
629 if (busId >= ARRAY_SIZE(mStmSpiDevs))
630 return -ENODEV;
631
632 struct StmSpiDev *pdev = &mStmSpiDevs[busId];
633
634 return dmaIrq(pdev->cfg->dmaBus, pdev->board->dmaRx.stream);
635 }
636
spiTxIrq(uint8_t busId)637 const enum IRQn spiTxIrq(uint8_t busId)
638 {
639 if (busId >= ARRAY_SIZE(mStmSpiDevs))
640 return -ENODEV;
641
642 struct StmSpiDev *pdev = &mStmSpiDevs[busId];
643
644 return dmaIrq(pdev->cfg->dmaBus, pdev->board->dmaTx.stream);
645 }
646