• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)&regs->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