114986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi/*
214986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * Copyright (C) 2016 The Android Open Source Project
314986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *
414986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * Licensed under the Apache License, Version 2.0 (the "License");
514986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * you may not use this file except in compliance with the License.
614986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * You may obtain a copy of the License at
714986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *
814986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *      http://www.apache.org/licenses/LICENSE-2.0
914986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *
1014986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * Unless required by applicable law or agreed to in writing, software
1114986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * distributed under the License is distributed on an "AS IS" BASIS,
1214986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * See the License for the specific language governing permissions and
1414986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * limitations under the License.
1514986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi */
1614986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi
174916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#include <errno.h>
184916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#include <string.h>
194916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
204916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#include <gpio.h>
214916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#include <spi.h>
224916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#include <spi_priv.h>
234916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#include <util.h>
2401ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema#include <atomicBitset.h>
2501ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema#include <atomic.h>
26ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema#include <platform.h>
274916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
28f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/cmsis.h>
29f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/dma.h>
30f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/gpio.h>
31f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/pwr.h>
32f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/exti.h>
33f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/syscfg.h>
34f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/spi.h>
35f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/plat.h>
364916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
374916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_CPHA                (1 << 0)
384916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_CPOL                (1 << 1)
394916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_MSTR                (1 << 2)
404916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
414916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_BR(x)               ((LOG2_CEIL(x) - 1) << 3)
424916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_BR_MIN              2
434916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_BR_MAX              256
444916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_BR_MASK             (0x7 << 3)
454916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
464916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_SPE                 (1 << 6)
474916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_LSBFIRST            (1 << 7)
488c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann#define SPI_CR1_SSI                 (1 << 8)
498c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann#define SPI_CR1_SSM                 (1 << 9)
504916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_RXONLY              (1 << 10)
514916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_DFF                 (1 << 11)
524916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_BIDIOE              (1 << 14)
534916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR1_BIDIMODE            (1 << 15)
544916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
554916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR2_TXEIE               (1 << 7)
564916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR2_RXNEIE              (1 << 6)
574916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR2_ERRIE               (1 << 5)
5883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann#define SPI_CR2_TXDMAEN             (1 << 1)
5983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann#define SPI_CR2_RXDMAEN             (1 << 0)
604916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR2_INT_MASK            (SPI_CR2_TXEIE | SPI_CR2_RXNEIE | SPI_CR2_ERRIE)
614916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
624916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_CR2_SSOE                (1 << 2)
634916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
644916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_SR_RXNE                 (1 << 0)
654916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_SR_TXE                  (1 << 1)
664916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define SPI_SR_BSY                  (1 << 7)
674916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
6838d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergstruct StmSpi {
694916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t CR1;
704916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t CR2;
714916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t SR;
724916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t DR;
734916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t CRCPR;
744916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t RXCRCR;
754916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t TXCRCR;
764916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t I2SCFGR;
774916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    volatile uint32_t I2SPR;
784916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann};
794916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
8038d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergstruct StmSpiState {
8138d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    uint8_t bitsPerWord;
8201ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema    uint8_t xferEnable;
83925bae58b5a27241ee56ca2de3e917798cb6ec77Greg Hackmann
84866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    uint16_t rxWord;
85925bae58b5a27241ee56ca2de3e917798cb6ec77Greg Hackmann    uint16_t txWord;
86869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
8783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    bool rxDone;
8883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    bool txDone;
8983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
90869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    struct ChainedIsr isrNss;
9118398435228c803389784c0407280e745d5a9bdeBen Fennema
9218398435228c803389784c0407280e745d5a9bdeBen Fennema    bool nssChange;
934916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann};
944916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
9538d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergstruct StmSpiCfg {
9638d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    struct StmSpi *regs;
974916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
981337f149cbf99cd9a52081f671f62dadcd3bb48cGreg Hackmann    uint32_t clockBus;
9938d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    uint32_t clockUnit;
1004916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
1014916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    IRQn_Type irq;
10283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
10383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    uint8_t dmaBus;
1044916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann};
1054916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
10638d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergstruct StmSpiDev {
10738d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    struct SpiDevice *base;
10807139a2ed11599600356935068c28877db47f1feGreg Hackmann    const struct StmSpiCfg *cfg;
109bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    const struct StmSpiBoardCfg *board;
11038d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    struct StmSpiState state;
1114916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
11271b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct Gpio *miso;
11371b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct Gpio *mosi;
11471b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct Gpio *sck;
11571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct Gpio *nss;
1164916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann};
1174916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
1183568682fec0484260cfe2b9ba0d1540f956c21cbDmitry Grinbergstatic inline struct Gpio *stmSpiGpioInit(uint32_t gpioNum, enum StmGpioSpeed speed, enum StmGpioAltFunc func)
1198c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann{
1203568682fec0484260cfe2b9ba0d1540f956c21cbDmitry Grinberg    struct Gpio *gpio = gpioRequest(gpioNum);
12184f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg
12284f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (gpio)
12384f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        gpioConfigAlt(gpio, speed, GPIO_PULL_NONE, GPIO_OUT_PUSH_PULL, func);
12471b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
12571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    return gpio;
1268c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann}
1278c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
1283568682fec0484260cfe2b9ba0d1540f956c21cbDmitry Grinbergstatic inline void stmSpiDataPullMode(struct StmSpiDev *pdev, enum StmGpioSpeed dataSpeed, enum GpioPullMode dataPull)
129a916fd8c0dce52dd6b219608d7481a11a01d44a7Greg Hackmann{
13071b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    gpioConfigAlt(pdev->miso, dataSpeed, dataPull, GPIO_OUT_PUSH_PULL, pdev->board->gpioFunc);
13171b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    gpioConfigAlt(pdev->mosi, dataSpeed, dataPull, GPIO_OUT_PUSH_PULL, pdev->board->gpioFunc);
132a916fd8c0dce52dd6b219608d7481a11a01d44a7Greg Hackmann}
133a916fd8c0dce52dd6b219608d7481a11a01d44a7Greg Hackmann
1343568682fec0484260cfe2b9ba0d1540f956c21cbDmitry Grinbergstatic inline void stmSpiSckPullMode(struct StmSpiDev *pdev, enum StmGpioSpeed sckSpeed, enum GpioPullMode sckPull)
135ad1df726050591a13fa41fe450a40d80dca7a448Greg Hackmann{
13671b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    gpioConfigAlt(pdev->sck, sckSpeed, sckPull, GPIO_OUT_PUSH_PULL, pdev->board->gpioFunc);
137ad1df726050591a13fa41fe450a40d80dca7a448Greg Hackmann}
138ad1df726050591a13fa41fe450a40d80dca7a448Greg Hackmann
13983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmannstatic inline void stmSpiStartDma(struct StmSpiDev *pdev,
14083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        const struct StmSpiDmaCfg *dmaCfg, const void *buf, uint8_t bitsPerWord,
14183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        bool minc, size_t size, DmaCallbackF callback, bool rx)
14283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann{
14383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
14483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct dmaMode mode;
14583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
14683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    memset(&mode, 0, sizeof(mode));
14783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
14883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (bitsPerWord == 8) {
14983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        mode.psize = DMA_SIZE_8_BITS;
15083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        mode.msize = DMA_SIZE_8_BITS;
15183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    } else {
15283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        mode.psize = DMA_SIZE_16_BITS;
15383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        mode.msize = DMA_SIZE_16_BITS;
15483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
15583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    mode.priority = DMA_PRIORITY_HIGH;
15683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    mode.direction = rx ? DMA_DIRECTION_PERIPH_TO_MEM :
15783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann            DMA_DIRECTION_MEM_TO_PERIPH;
15883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    mode.periphAddr = (uintptr_t)&regs->DR;
15983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    mode.minc = minc;
16083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    mode.channel = dmaCfg->channel;
16183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
16283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    dmaStart(pdev->cfg->dmaBus, dmaCfg->stream, buf, size, &mode, callback,
16383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann            pdev);
16483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann}
16583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
166ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic inline int stmSpiEnable(struct StmSpiDev *pdev,
167ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        const struct SpiMode *mode, bool master)
1684916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
16907139a2ed11599600356935068c28877db47f1feGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
17001ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema    struct StmSpiState *state = &pdev->state;
1714916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
17238d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    if (mode->bitsPerWord != 8 &&
17338d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg            mode->bitsPerWord != 16)
1744916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        return -EINVAL;
1754916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
176ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    unsigned int div;
177ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    if (master) {
178ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        if (!mode->speed)
179ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann            return -EINVAL;
180ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
181ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        uint32_t pclk = pwrGetBusSpeed(PERIPH_BUS_AHB1);
182ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        div = pclk / mode->speed;
183ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        if (div > SPI_CR1_BR_MAX)
184ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann            return -EINVAL;
185ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        else if (div < SPI_CR1_BR_MIN)
186ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann            div = SPI_CR1_BR_MIN;
187ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    }
1884916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
18901ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema    atomicWriteByte(&state->xferEnable, false);
19001ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema
19183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    state->txWord = mode->txWord;
19283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    state->bitsPerWord = mode->bitsPerWord;
19383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
1941337f149cbf99cd9a52081f671f62dadcd3bb48cGreg Hackmann    pwrUnitClock(pdev->cfg->clockBus, pdev->cfg->clockUnit, true);
1954916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
196ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    if (master) {
197ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        regs->CR1 &= ~SPI_CR1_BR_MASK;
198ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        regs->CR1 |= SPI_CR1_BR(div);
199ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    }
2004916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
2014916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    if (mode->cpol == SPI_CPOL_IDLE_LO)
2024916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 &= ~SPI_CR1_CPOL;
2034916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    else
2044916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 |= SPI_CR1_CPOL;
2054916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
2064916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    if (mode->cpha == SPI_CPHA_LEADING_EDGE)
2074916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 &= ~SPI_CR1_CPHA;
2084916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    else
2094916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 |= SPI_CR1_CPHA;
2104916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
21138d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    if (mode->bitsPerWord == 8)
2124916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 &= ~SPI_CR1_DFF;
2134916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    else
2144916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 |= SPI_CR1_DFF;
2154916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
2164916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    if (mode->format == SPI_FORMAT_MSB_FIRST)
2174916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 &= ~SPI_CR1_LSBFIRST;
2184916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    else
2194916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        regs->CR1 |= SPI_CR1_LSBFIRST;
2204916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
2218c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    if (master)
2228c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann        regs->CR1 |= SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_MSTR;
2238c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    else
2248c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann        regs->CR1 &= ~(SPI_CR1_SSM | SPI_CR1_MSTR);
2254916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
2264916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    return 0;
2274916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
2284916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
229ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic int stmSpiMasterStartSync(struct SpiDevice *dev, spi_cs_t cs,
230ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        const struct SpiMode *mode)
231ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann{
232ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
2338c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
2348c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    int err = stmSpiEnable(pdev, mode, true);
2358c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    if (err < 0)
2368c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann        return err;
2378c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
238bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    stmSpiDataPullMode(pdev, pdev->board->gpioSpeed, pdev->board->gpioPull);
239bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    stmSpiSckPullMode(pdev, pdev->board->gpioSpeed, mode->cpol ? GPIO_PULL_UP : GPIO_PULL_DOWN);
240ad1df726050591a13fa41fe450a40d80dca7a448Greg Hackmann
24171b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    if (!pdev->nss)
24271b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        pdev->nss = gpioRequest(cs);
24384f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (!pdev->nss)
24484f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        return -ENODEV;
24571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    gpioConfigOutput(pdev->nss, pdev->board->gpioSpeed, pdev->board->gpioPull, GPIO_OUT_PUSH_PULL, 1);
2468c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
2478c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    return 0;
248ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann}
249ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
250ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic int stmSpiSlaveStartSync(struct SpiDevice *dev,
251ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        const struct SpiMode *mode)
252ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann{
253ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
254a916fd8c0dce52dd6b219608d7481a11a01d44a7Greg Hackmann
255bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    stmSpiDataPullMode(pdev, pdev->board->gpioSpeed, GPIO_PULL_NONE);
256bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    stmSpiSckPullMode(pdev, pdev->board->gpioSpeed, GPIO_PULL_NONE);
257a916fd8c0dce52dd6b219608d7481a11a01d44a7Greg Hackmann
25871b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    if (!pdev->nss)
25971b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        pdev->nss = stmSpiGpioInit(pdev->board->gpioNss, pdev->board->gpioSpeed, pdev->board->gpioFunc);
26084f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (!pdev->nss)
26184f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        return -ENODEV;
26284f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg
263ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    return stmSpiEnable(pdev, mode, false);
264ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann}
265ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
266ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic inline bool stmSpiIsMaster(struct StmSpiDev *pdev)
267ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann{
268ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
269ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    return !!(regs->CR1 & SPI_CR1_MSTR);
270ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann}
271ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
27283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmannstatic void stmSpiDone(struct StmSpiDev *pdev, int err)
2734916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
27407139a2ed11599600356935068c28877db47f1feGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
27518398435228c803389784c0407280e745d5a9bdeBen Fennema    struct StmSpiState *state = &pdev->state;
27618398435228c803389784c0407280e745d5a9bdeBen Fennema
277287671677bb946b266dc4c8fc39582533272363cBen Fennema    if (pdev->board->sleepDev >= 0)
278287671677bb946b266dc4c8fc39582533272363cBen Fennema        platReleaseDevInSleepMode(pdev->board->sleepDev);
279ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema
28083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    while (regs->SR & SPI_SR_BSY)
28183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        ;
2824916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
28383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (stmSpiIsMaster(pdev)) {
28484f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        if (state->nssChange && pdev->nss)
28571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg            gpioSet(pdev->nss, 1);
28683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        spiMasterRxTxDone(pdev->base, err);
28783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    } else {
28883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        regs->CR2 = SPI_CR2_TXEIE;
28983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        spiSlaveRxTxDone(pdev->base, err);
29083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
29183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann}
292ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
29383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmannstatic void stmSpiRxDone(void *cookie, uint16_t bytesLeft, int err)
29483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann{
29583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiDev *pdev = cookie;
29683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
29783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiState *state = &pdev->state;
2984916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
29983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR2 &= ~SPI_CR2_RXDMAEN;
30083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    state->rxDone = true;
3014916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
30283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (state->txDone) {
30383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        atomicWriteByte(&state->xferEnable, false);
30483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        stmSpiDone(pdev, err);
30583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
30683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann}
30701ca2d608831afaa5a2891339d9ad8cbd60bbd5aBen Fennema
30883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmannstatic void stmSpiTxDone(void *cookie, uint16_t bytesLeft, int err)
30983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann{
31083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiDev *pdev = cookie;
31183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
31283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiState *state = &pdev->state;
313ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
31483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR2 &= ~SPI_CR2_TXDMAEN;
31583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    state->txDone = true;
316ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
31783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (state->rxDone) {
31883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        atomicWriteByte(&state->xferEnable, false);
31983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        stmSpiDone(pdev, err);
32083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
3214916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
3224916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
323ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic int stmSpiRxTx(struct SpiDevice *dev, void *rxBuf, const void *txBuf,
324ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann        size_t size, const struct SpiMode *mode)
3254916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
32683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
32783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
32883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiState *state = &pdev->state;
329866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    bool rxMinc = true, txMinc = true;
33083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    uint32_t cr2 = SPI_CR2_TXDMAEN;
33183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
33283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (atomicXchgByte(&state->xferEnable, true) == true)
33383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        return -EBUSY;
33483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
33584f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (stmSpiIsMaster(pdev) && pdev->nss)
33671b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        gpioSet(pdev->nss, 0);
33718398435228c803389784c0407280e745d5a9bdeBen Fennema
338866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    state->rxDone = false;
33983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    state->txDone = false;
34018398435228c803389784c0407280e745d5a9bdeBen Fennema    state->nssChange = mode->nssChange;
34183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
342866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    /* In master mode, if RX is ignored at any point, then turning it on
343866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * later may cause the SPI/DMA controllers to "receive" a stale byte
344866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * sitting in a FIFO somewhere (even when their respective registers say
345866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * their FIFOs are empty, and even if the SPI FIFO is explicitly cleared).
346866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * Work around this by DMAing bytes we don't care about into a throwaway
347866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * 1-word buffer.
348866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     *
349866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * In slave mode, this specific WAR sometimes causes bigger problems
350866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * (the first byte TXed is sometimes dropped or corrupted).  Slave mode
351866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     * has its own WARs below.
352866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann     */
353866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    if (!rxBuf && stmSpiIsMaster(pdev)) {
354866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann        rxBuf = &state->rxWord;
355866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann        rxMinc = false;
356866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    }
357866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann
35883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (rxBuf) {
35983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        stmSpiStartDma(pdev, &pdev->board->dmaRx, rxBuf, mode->bitsPerWord,
360866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann                rxMinc, size, stmSpiRxDone, true);
36183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        cr2 |= SPI_CR2_RXDMAEN;
362866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann    } else {
363866a4f391bfb4bd207f890e41b9b305f9c3f179fGreg Hackmann        state->rxDone = true;
36483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
36583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
36683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (!txBuf) {
36783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        txBuf = &state->txWord;
36883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        txMinc = false;
36983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
37083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    stmSpiStartDma(pdev, &pdev->board->dmaTx, txBuf, mode->bitsPerWord, txMinc,
37183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann            size, stmSpiTxDone, false);
37283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
37383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    /* Ensure the TXE and RXNE bits are cleared; otherwise the DMA controller
37483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     * may "receive" the byte sitting in the SPI controller's FIFO right now,
37583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     * or drop/corrupt the first TX byte.  Timing is crucial here, so do it
37683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     * right before enabling DMA.
37783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     */
37883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (!stmSpiIsMaster(pdev)) {
37983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        regs->CR2 &= ~SPI_CR2_TXEIE;
380f22f291bd2bd29fd6c68f0a1208c196ab57c6be7Ben Fennema        NVIC_ClearPendingIRQ(pdev->cfg->irq);
38183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
38283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        if (regs->SR & SPI_SR_RXNE)
38383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann            (void)regs->DR;
38483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
38583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        if (regs->SR & SPI_SR_TXE)
38683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann            regs->DR = mode->txWord;
38783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    }
38883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
3891e917212d60ca09ce55ebd81ee7753313e112128Ben Fennema    if (pdev->board->sleepDev >= 0)
3901e917212d60ca09ce55ebd81ee7753313e112128Ben Fennema        platRequestDevInSleepMode(pdev->board->sleepDev, 12);
3911e917212d60ca09ce55ebd81ee7753313e112128Ben Fennema
39283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR2 = cr2;
39383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR1 |= SPI_CR1_SPE;
39483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
395ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema
39683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    return 0;
397ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann}
3984916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
399ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic int stmSpiSlaveIdle(struct SpiDevice *dev, const struct SpiMode *mode)
400ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann{
40183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
40283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
40383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    struct StmSpiState *state = &pdev->state;
40483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
40583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    if (atomicXchgByte(&state->xferEnable, true) == true)
40683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        return -EBUSY;
40783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
40883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR2 = SPI_CR2_TXEIE;
40983f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR1 |= SPI_CR1_SPE;
41083f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
41183f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    atomicXchgByte(&state->xferEnable, false);
41283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    return 0;
4134916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
4144916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
4158c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmannstatic inline void stmSpiDisable(struct SpiDevice *dev, bool master)
4164916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
417ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
41807139a2ed11599600356935068c28877db47f1feGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
4194916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
420925bae58b5a27241ee56ca2de3e917798cb6ec77Greg Hackmann    while (regs->SR & SPI_SR_BSY)
421925bae58b5a27241ee56ca2de3e917798cb6ec77Greg Hackmann        ;
4228c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
423ad1df726050591a13fa41fe450a40d80dca7a448Greg Hackmann    if (master) {
424bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann        stmSpiSckPullMode(pdev, pdev->board->gpioSpeed, pdev->board->gpioPull);
425ad1df726050591a13fa41fe450a40d80dca7a448Greg Hackmann    }
4268c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
42783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR2 &= ~(SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN | SPI_CR2_TXEIE);
4284916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    regs->CR1 &= ~SPI_CR1_SPE;
429ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    pwrUnitClock(pdev->cfg->clockBus, pdev->cfg->clockUnit, false);
4308c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann}
4318c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann
4328c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmannstatic int stmSpiMasterStopSync(struct SpiDevice *dev)
4338c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann{
43471b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct StmSpiDev *pdev = dev->pdata;
43571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
43684f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (pdev->nss) {
43784f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        gpioSet(pdev->nss, 1);
43871b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        gpioRelease(pdev->nss);
43984f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    }
44071b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
4418c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    stmSpiDisable(dev, true);
44284f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    pdev->nss = NULL;
4438c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    return 0;
4448c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann}
4454916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
4468c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmannstatic int stmSpiSlaveStopSync(struct SpiDevice *dev)
4478c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann{
44871b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct StmSpiDev *pdev = dev->pdata;
44971b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
45071b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    if (pdev->nss)
45171b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        gpioRelease(pdev->nss);
45271b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
4538c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    stmSpiDisable(dev, false);
45484f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    pdev->nss = NULL;
455ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    return 0;
4564916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
4574916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
458869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmannstatic bool stmSpiExtiIsr(struct ChainedIsr *isr)
459869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann{
460869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    struct StmSpiState *state = container_of(isr, struct StmSpiState, isrNss);
461869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    struct StmSpiDev *pdev = container_of(state, struct StmSpiDev, state);
462869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
46384f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (pdev->nss && !extiIsPendingGpio(pdev->nss))
464869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann        return false;
465869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
466869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    spiSlaveCsInactive(pdev->base);
46784f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    if (pdev->nss)
46884f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        extiClearPendingGpio(pdev->nss);
469869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    return true;
470869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann}
471869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
472869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmannstatic void stmSpiSlaveSetCsInterrupt(struct SpiDevice *dev, bool enabled)
473869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann{
474869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
475869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    struct ChainedIsr *isr = &pdev->state.isrNss;
476869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
477869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    if (enabled) {
478869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann        isr->func = stmSpiExtiIsr;
479869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
48084f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        if (pdev->nss) {
48184f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg            syscfgSetExtiPort(pdev->nss);
48284f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg            extiEnableIntGpio(pdev->nss, EXTI_TRIGGER_RISING);
48384f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        }
484bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann        extiChainIsr(pdev->board->irqNss, isr);
485869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    } else {
486bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann        extiUnchainIsr(pdev->board->irqNss, isr);
48784f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg        if (pdev->nss)
48884f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg            extiDisableIntGpio(pdev->nss);
489869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    }
490869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann}
491869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
492869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmannstatic bool stmSpiSlaveCsIsActive(struct SpiDevice *dev)
493869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann{
494869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    struct StmSpiDev *pdev = dev->pdata;
49584f82ecc7368fde3670b46e4b634f5c716ccdd70Dmitry Grinberg    return pdev->nss && !gpioGet(pdev->nss);
496869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann}
497869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
498ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmannstatic inline void stmSpiTxe(struct StmSpiDev *pdev)
4994916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
50007139a2ed11599600356935068c28877db47f1feGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
5014916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
50283f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    /**
50383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     * n.b.: if nothing handles the TXE interrupt in slave mode, the SPI
50483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     * controller will just keep reading the existing value from DR anytime it
50583f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     * needs data
50683f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann     */
50783f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->DR = pdev->state.txWord;
50883f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann    regs->CR2 &= ~SPI_CR2_TXEIE;
5094916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
5104916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
51138d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergstatic void stmSpiIsr(struct StmSpiDev *pdev)
5124916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
51307139a2ed11599600356935068c28877db47f1feGreg Hackmann    struct StmSpi *regs = pdev->cfg->regs;
5144916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
515ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    if (regs->SR & SPI_SR_TXE) {
51638d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg        stmSpiTxe(pdev);
5174916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    }
518ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
519ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    /* TODO: error conditions */
5204916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
5214916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
5222fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennemastatic int stmSpiRelease(struct SpiDevice *dev)
5232fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema{
5242fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema    struct StmSpiDev *pdev = dev->pdata;
5252fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema
5262fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema    NVIC_DisableIRQ(pdev->cfg->irq);
5272fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema
5282fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema    pdev->base = NULL;
5292fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema    return 0;
5302fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema}
5312fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema
5324916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann#define DECLARE_IRQ_HANDLER(_n)             \
5334916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    void SPI##_n##_IRQHandler();            \
5344916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    void SPI##_n##_IRQHandler()             \
5354916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    {                                       \
53638d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg        stmSpiIsr(&mStmSpiDevs[_n - 1]); \
5374916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    }
5384916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
53938d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergconst struct SpiDevice_ops mStmSpiOps = {
54038d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    .masterStartSync = stmSpiMasterStartSync,
541ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    .masterRxTx = stmSpiRxTx,
5428c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    .masterStopSync = stmSpiMasterStopSync,
543ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
544ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    .slaveStartSync = stmSpiSlaveStartSync,
545ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    .slaveIdle = stmSpiSlaveIdle,
546ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann    .slaveRxTx = stmSpiRxTx,
5478c49df92e18c9e828f85d0d05bff8d9e70a8e9fcGreg Hackmann    .slaveStopSync = stmSpiSlaveStopSync,
548ead4eb3243c8f1a61ced9a97c3d91c9104bc1e9eGreg Hackmann
549869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    .slaveSetCsInterrupt = stmSpiSlaveSetCsInterrupt,
550869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann    .slaveCsIsActive = stmSpiSlaveCsIsActive,
551869f1aee3d9d2833bd6739b441e2def728b7f40eGreg Hackmann
5522fd20a565b6792cf5fb6ca4485a8b0ffa62682e7Ben Fennema    .release = stmSpiRelease,
5534916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann};
5544916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
55507139a2ed11599600356935068c28877db47f1feGreg Hackmannstatic const struct StmSpiCfg mStmSpiCfgs[] = {
5564916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    [0] = {
55707139a2ed11599600356935068c28877db47f1feGreg Hackmann        .regs = (struct StmSpi *)SPI1_BASE,
5584916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
5591337f149cbf99cd9a52081f671f62dadcd3bb48cGreg Hackmann        .clockBus = PERIPH_BUS_APB2,
56007139a2ed11599600356935068c28877db47f1feGreg Hackmann        .clockUnit = PERIPH_APB2_SPI1,
5614916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
56207139a2ed11599600356935068c28877db47f1feGreg Hackmann        .irq = SPI1_IRQn,
56383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
56483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        .dmaBus = SPI1_DMA_BUS,
5654916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    },
56677eed017e95498248ff9ead1b5797d0f7fb601e2Sean Wan    [1] = {
56794232616d933f90ae346844ec1022664eef780e0Ben Fennema        .regs = (struct StmSpi *)SPI2_BASE,
56877eed017e95498248ff9ead1b5797d0f7fb601e2Sean Wan
56994232616d933f90ae346844ec1022664eef780e0Ben Fennema        .clockBus = PERIPH_BUS_APB1,
57094232616d933f90ae346844ec1022664eef780e0Ben Fennema        .clockUnit = PERIPH_APB1_SPI2,
57177eed017e95498248ff9ead1b5797d0f7fb601e2Sean Wan
57294232616d933f90ae346844ec1022664eef780e0Ben Fennema        .irq = SPI2_IRQn,
57383f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann
57483f8ebde8294106d4474fc2fc5e0aa4c674ae48dGreg Hackmann        .dmaBus = SPI2_DMA_BUS,
57577eed017e95498248ff9ead1b5797d0f7fb601e2Sean Wan    },
57643833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol    [2] = {
57743833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol        .regs = (struct StmSpi *)SPI3_BASE,
57843833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol
57943833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol        .clockBus = PERIPH_BUS_APB1,
58043833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol        .clockUnit = PERIPH_APB1_SPI3,
58143833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol
58243833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol        .irq = SPI3_IRQn,
58343833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol
58443833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol        .dmaBus = SPI3_DMA_BUS,
58543833ff041d8366e37e8fc18d535fc7a3cf90080Andrew Rossignol    },
5864916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann};
58707139a2ed11599600356935068c28877db47f1feGreg Hackmann
58807139a2ed11599600356935068c28877db47f1feGreg Hackmannstatic struct StmSpiDev mStmSpiDevs[ARRAY_SIZE(mStmSpiCfgs)];
5894916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg HackmannDECLARE_IRQ_HANDLER(1)
59077eed017e95498248ff9ead1b5797d0f7fb601e2Sean WanDECLARE_IRQ_HANDLER(2)
59143833ff041d8366e37e8fc18d535fc7a3cf90080Andrew RossignolDECLARE_IRQ_HANDLER(3)
5924916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
59307139a2ed11599600356935068c28877db47f1feGreg Hackmannstatic void stmSpiInit(struct StmSpiDev *pdev, const struct StmSpiCfg *cfg,
594bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann        const struct StmSpiBoardCfg *board, struct SpiDevice *dev)
5954916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
59671b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    pdev->miso = stmSpiGpioInit(board->gpioMiso, board->gpioSpeed, board->gpioFunc);
59771b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    pdev->mosi = stmSpiGpioInit(board->gpioMosi, board->gpioSpeed, board->gpioFunc);
59871b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    pdev->sck = stmSpiGpioInit(board->gpioSclk, board->gpioSpeed, board->gpioFunc);
5994916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
6004916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    NVIC_EnableIRQ(cfg->irq);
6014916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
6024916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    pdev->base = dev;
60307139a2ed11599600356935068c28877db47f1feGreg Hackmann    pdev->cfg = cfg;
604bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    pdev->board = board;
6054916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
6064916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
60738d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinbergint spiRequest(struct SpiDevice *dev, uint8_t busId)
6084916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann{
60938d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    if (busId >= ARRAY_SIZE(mStmSpiDevs))
6104916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann        return -ENODEV;
6114916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
612bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    const struct StmSpiBoardCfg *board = boardStmSpiCfg(busId);
613bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann    if (!board)
614396f58ffc174cc626b1bd9df2290504c4525b936Greg Hackmann        return -ENODEV;
615396f58ffc174cc626b1bd9df2290504c4525b936Greg Hackmann
61638d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    struct StmSpiDev *pdev = &mStmSpiDevs[busId];
61707139a2ed11599600356935068c28877db47f1feGreg Hackmann    const struct StmSpiCfg *cfg = &mStmSpiCfgs[busId];
6184916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    if (!pdev->base)
619bfaf30a2f443d0a9d0bcf3a3f314aa0d023ae64eGreg Hackmann        stmSpiInit(pdev, cfg, board, dev);
6204916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann
6214916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    memset(&pdev->state, 0, sizeof(pdev->state));
62238d2948bf8eec7b52d8b24d532cc92b8c76bc0c7Dmitry Grinberg    dev->ops = &mStmSpiOps;
6234916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    dev->pdata = pdev;
6244916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann    return 0;
6254916eb0b0c0f8afbca2ed51d8dead799eae98a5bGreg Hackmann}
626b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema
627b6ce271e41eef25e45ffb699e912801489028b47Ben Fennemaconst enum IRQn spiRxIrq(uint8_t busId)
628b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema{
629b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema    if (busId >= ARRAY_SIZE(mStmSpiDevs))
630b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema        return -ENODEV;
631b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema
632b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema    struct StmSpiDev *pdev = &mStmSpiDevs[busId];
633b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema
634b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema    return dmaIrq(pdev->cfg->dmaBus, pdev->board->dmaRx.stream);
635b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema}
636b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema
637b6ce271e41eef25e45ffb699e912801489028b47Ben Fennemaconst enum IRQn spiTxIrq(uint8_t busId)
638b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema{
639b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema    if (busId >= ARRAY_SIZE(mStmSpiDevs))
640b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema        return -ENODEV;
641b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema
642b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema    struct StmSpiDev *pdev = &mStmSpiDevs[busId];
643b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema
644b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema    return dmaIrq(pdev->cfg->dmaBus, pdev->board->dmaTx.stream);
645b6ce271e41eef25e45ffb699e912801489028b47Ben Fennema}
646