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
170840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <errno.h>
180840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <stdint.h>
191a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann#include <string.h>
200840b67ad4db1415094691100441dffe913f76abGreg Hackmann
210840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <gpio.h>
22a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg#include <i2c.h>
230840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <seos.h>
240840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <util.h>
2571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg#include <gpio.h>
2681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#include <atomicBitset.h>
2781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#include <atomic.h>
28ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema#include <platform.h>
290840b67ad4db1415094691100441dffe913f76abGreg Hackmann
30f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/cmsis.h>
31f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/dma.h>
32f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/gpio.h>
33f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/i2c.h>
34f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/pwr.h>
35f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/plat.h>
360840b67ad4db1415094691100441dffe913f76abGreg Hackmann
37f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <cpu/barrier.h>
3881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
3981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#define I2C_VERBOSE_DEBUG       0
4081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#define I2C_MAX_QUEUE_DEPTH     5
410840b67ad4db1415094691100441dffe913f76abGreg Hackmann
420840b67ad4db1415094691100441dffe913f76abGreg Hackmann#if I2C_VERBOSE_DEBUG
439ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann#define i2c_log_debug(x) osLog(LOG_DEBUG, x "\n")
440840b67ad4db1415094691100441dffe913f76abGreg Hackmann#else
450840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define i2c_log_debug(x) do {} while(0)
460840b67ad4db1415094691100441dffe913f76abGreg Hackmann#endif
470840b67ad4db1415094691100441dffe913f76abGreg Hackmann
480840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_PE          (1 << 0)
490840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SMBUS       (1 << 1)
500840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SMBTYPE     (1 << 3)
510840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENARP       (1 << 4)
520840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENPEC       (1 << 5)
530840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENGC        (1 << 6)
540840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_NOSTRETCH   (1 << 7)
550840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_START       (1 << 8)
560840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_STOP        (1 << 9)
570840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ACK         (1 << 10)
580840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_POS         (1 << 11)
590840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_PEC         (1 << 12)
600840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ALERT       (1 << 13)
610840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SWRST       (1 << 15)
620840b67ad4db1415094691100441dffe913f76abGreg Hackmann
63c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CR2_FREQ(x)     ((x) & I2C_CR2_FREQ_MASK)
640840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_FREQ_MASK   0x3F
650840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITERREN     (1 << 8)
660840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITEVTEN     (1 << 9)
670840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITBUFEN     (1 << 10)
680840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_DMAEN       (1 << 11)
690840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_LAST        (1 << 12)
700840b67ad4db1415094691100441dffe913f76abGreg Hackmann
71c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD7(x)    (((x) & I2C_OAR1_ADD7_MASK) << 1)
72c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD7_MASK  0x7F
73c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD10(x)   ((x) & I2C_OAR1_ADD10_MASK)
74c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD10_MASK 0x3FF
750840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_OAR1_ADDMODE    (1 << 15)
760840b67ad4db1415094691100441dffe913f76abGreg Hackmann
770840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_SB          (1 << 0)
780840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ADDR        (1 << 1)
790840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_BTF         (1 << 2)
800840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ADD10       (1 << 3)
810840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_STOPF       (1 << 4)
820840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_RXNE        (1 << 6)
830840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_TXE         (1 << 7)
840840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_BERR        (1 << 8)
850840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ARLO        (1 << 9)
860840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_AF          (1 << 10)
870840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_OVR         (1 << 11)
880840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_PECERR      (1 << 12)
890840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_TIMEOUT     (1 << 14)
900840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_SMBALERT    (1 << 15)
910840b67ad4db1415094691100441dffe913f76abGreg Hackmann
920840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_MSL         (1 << 0)
930840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_BUSY        (1 << 1)
940840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_TRA         (1 << 2)
950840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_GENCALL     (1 << 4)
960840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_SMBDEFAULT  (1 << 5)
970840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_SMBHOST     (1 << 6)
980840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_DUALF       (1 << 7)
990840b67ad4db1415094691100441dffe913f76abGreg Hackmann
100c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR(x)          ((x) & I2C_CCR_MASK)
101c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_MASK        0xFFF
102c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_DUTY_16_9   (1 << 14)
103c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_FM          (1 << 15)
104c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
105c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_TRISE(x)        ((x) & I2C_TRISE_MASK)
106c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_TRISE_MASK      0x3F
107c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
108a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2c {
1090840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CR1;
1100840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CR2;
1110840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t OAR1;
1120840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t OAR2;
1130840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t DR;
1140840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t SR1;
1150840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t SR2;
1160840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CCR;
1170840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t TRISE;
1180840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t FLTR;
1190840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1200840b67ad4db1415094691100441dffe913f76abGreg Hackmann
12181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemaenum StmI2cSpiMasterState
12281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
12381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_IDLE,
12481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_START,
12581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_TX_ADDR,
12681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_TX_DATA,
12781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_RX_ADDR,
12881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_RX_DATA,
12981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
13081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
131a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct I2cStmState {
1320840b67ad4db1415094691100441dffe913f76abGreg Hackmann    struct {
1330840b67ad4db1415094691100441dffe913f76abGreg Hackmann        union {
1340840b67ad4db1415094691100441dffe913f76abGreg Hackmann            uint8_t *buf;
1350840b67ad4db1415094691100441dffe913f76abGreg Hackmann            const uint8_t *cbuf;
1369ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            uint8_t byte;
1370840b67ad4db1415094691100441dffe913f76abGreg Hackmann        };
1380840b67ad4db1415094691100441dffe913f76abGreg Hackmann        size_t size;
1390840b67ad4db1415094691100441dffe913f76abGreg Hackmann        size_t offset;
1409ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        bool preamble;
1410840b67ad4db1415094691100441dffe913f76abGreg Hackmann
142a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        I2cCallbackF callback;
1430840b67ad4db1415094691100441dffe913f76abGreg Hackmann        void *cookie;
1440840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } rx, tx;
1450840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1460840b67ad4db1415094691100441dffe913f76abGreg Hackmann    enum {
147c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_DISABLED,
148c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_SLAVE,
149c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_MASTER,
150c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } mode;
151c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
152c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    enum {
153c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_SLAVE_IDLE,
1540840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_RX_ARMED,
1550840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_RX,
1560840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_TX_ARMED,
1570840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_TX,
158a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    } slaveState;
159c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
16081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    // StmI2cSpiMasterState
16181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState;
162c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    uint16_t tid;
1630840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1640840b67ad4db1415094691100441dffe913f76abGreg Hackmann
165a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2cCfg {
166a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct StmI2c *regs;
1670840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1680840b67ad4db1415094691100441dffe913f76abGreg Hackmann    uint32_t clock;
1690840b67ad4db1415094691100441dffe913f76abGreg Hackmann
170895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    IRQn_Type irqEv;
171895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    IRQn_Type irqEr;
1720840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1730840b67ad4db1415094691100441dffe913f76abGreg Hackmann
174a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2cDev {
175895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg;
176de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board;
177a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState state;
1780840b67ad4db1415094691100441dffe913f76abGreg Hackmann
17981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t next;
18081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t last;
18181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
18271b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct Gpio *scl;
18371b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    struct Gpio *sda;
184342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg
185342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg    uint8_t addr;
1860840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1870840b67ad4db1415094691100441dffe913f76abGreg Hackmann
18881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic const struct StmI2cCfg mStmI2cCfgs[] = {
18981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [0] = {
19081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C1_BASE,
19181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C1,
19381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C1_EV_IRQn,
19581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C1_ER_IRQn,
19681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
19781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [1] = {
19881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C2_BASE,
19981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
20081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C2,
20181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
20281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C2_EV_IRQn,
20381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C2_ER_IRQn,
20481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
20581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [2] = {
20681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C3_BASE,
20781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
20881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C3,
20981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C3_EV_IRQn,
21181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C3_ER_IRQn,
21281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
21381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
21481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic struct StmI2cDev mStmI2cDevs[ARRAY_SIZE(mStmI2cCfgs)];
21681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastruct StmI2cXfer
21881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
21981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t        id;
22081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    const void     *txBuf;
22181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    size_t          txSize;
22281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    void           *rxBuf;
22381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    size_t          rxSize;
22481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    I2cCallbackF    callback;
22581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    void           *cookie;
226342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg    uint8_t         busId; /* for us these are both fine in a uint 8 */
227342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg    uint8_t         addr;
228f62fa5ad2731c3f0711eacc4a623ed6cfd3e05beBen Fennema    uint16_t        tid;
22981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
23081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
23181be7381e3399a0ff4c54222987ab7bd0b1169dfBen FennemaATOMIC_BITSET_DECL(mXfersValid, I2C_MAX_QUEUE_DEPTH, static);
23281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic struct StmI2cXfer mXfers[I2C_MAX_QUEUE_DEPTH] = { };
23381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
23481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic inline struct StmI2cXfer *stmI2cGetXfer(void)
23581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
23681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    int32_t idx = atomicBitsetFindClearAndSet(mXfersValid);
23781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
23881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (idx < 0)
23981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return NULL;
24081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    else
24181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return mXfers + idx;
24281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema}
24381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
24481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic inline void stmI2cPutXfer(struct StmI2cXfer *xfer)
24581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
24681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (xfer)
24781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicBitsetClearBit(mXfersValid, xfer - mXfers);
24881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema}
24981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
250b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cAckEnable(struct StmI2cDev *pdev)
2510840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
252895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 |= I2C_CR1_ACK;
2530840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2540840b67ad4db1415094691100441dffe913f76abGreg Hackmann
255b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cAckDisable(struct StmI2cDev *pdev)
2560840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
257895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 &= ~I2C_CR1_ACK;
2580840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2590840b67ad4db1415094691100441dffe913f76abGreg Hackmann
2601a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cDmaEnable(struct StmI2cDev *pdev)
2611a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
2621a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    pdev->cfg->regs->CR2 |= I2C_CR2_DMAEN;
2631a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
2641a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
2651a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cDmaDisable(struct StmI2cDev *pdev)
2661a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
2671a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    pdev->cfg->regs->CR2 &= ~I2C_CR2_DMAEN;
2681a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
2691a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
270b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cStopEnable(struct StmI2cDev *pdev)
271c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
2726b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
2736b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2746b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    while (regs->CR1 & (I2C_CR1_STOP | I2C_CR1_START))
2756b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann        ;
2766b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    regs->CR1 |= I2C_CR1_STOP;
2776b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann}
2786b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2796b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmannstatic inline void stmI2cStartEnable(struct StmI2cDev *pdev)
2806b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann{
2816b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
2826b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2836b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    while (regs->CR1 & (I2C_CR1_STOP | I2C_CR1_START))
2846b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann        ;
2856b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    regs->CR1 |= I2C_CR1_START;
286c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
287c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
288b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cIrqEnable(struct StmI2cDev *pdev,
2890840b67ad4db1415094691100441dffe913f76abGreg Hackmann        uint32_t mask)
2900840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
291895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR2 |= mask;
2920840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2930840b67ad4db1415094691100441dffe913f76abGreg Hackmann
294b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cIrqDisable(struct StmI2cDev *pdev,
2950840b67ad4db1415094691100441dffe913f76abGreg Hackmann        uint32_t mask)
2960840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
297895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR2 &= ~mask;
2980840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2990840b67ad4db1415094691100441dffe913f76abGreg Hackmann
300a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cEnable(struct StmI2cDev *pdev)
3010840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
302895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 |= I2C_CR1_PE;
3030840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3040840b67ad4db1415094691100441dffe913f76abGreg Hackmann
305a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cDisable(struct StmI2cDev *pdev)
3060840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
307895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 &= ~I2C_CR1_PE;
3080840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3090840b67ad4db1415094691100441dffe913f76abGreg Hackmann
310a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cSpeedSet(struct StmI2cDev *pdev,
311342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg        const uint32_t speed)
312c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
313895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
314c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    int ccr, ccr_1, ccr_2;
315c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    int apb1_clk;
316c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
317c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    apb1_clk = pwrGetBusSpeed(PERIPH_BUS_APB1);
318c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
319c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    regs->CR2 = (regs->CR2 & ~I2C_CR2_FREQ_MASK) |
320c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema                 I2C_CR2_FREQ(apb1_clk / 1000000);
321c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
322c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (speed <= 100000) {
323c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr = apb1_clk / (speed * 2);
324c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr < 4)
325c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr = 4;
326c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->CCR = I2C_CCR(ccr);
327c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
328c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->TRISE = I2C_TRISE((apb1_clk / 1000000) + 1);
329c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (speed <= 400000) {
330c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr_1 = apb1_clk / (speed * 3);
331c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr_1 == 0 || apb1_clk / (ccr_1 * 3) > speed)
332c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr_1 ++;
333c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr_2 = apb1_clk / (speed * 25);
334c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr_2 == 0 || apb1_clk / (ccr_2 * 25) > speed)
335c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr_2 ++;
336c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
337c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if ((apb1_clk / (ccr_1 * 3)) > (apb1_clk / (ccr_2 * 25)))
338c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->CCR = I2C_CCR_FM | I2C_CCR(ccr_1);
339c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        else
340c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->CCR = I2C_CCR_FM | I2C_CCR_DUTY_16_9 | I2C_CCR(ccr_2);
341c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
342c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->TRISE = I2C_TRISE(((3*apb1_clk)/10000000) + 1);
343c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
344c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
345c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
346a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cSlaveIdle(struct StmI2cDev *pdev)
3470840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
348a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
3490840b67ad4db1415094691100441dffe913f76abGreg Hackmann
350a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    state->slaveState = STM_I2C_SLAVE_RX_ARMED;
351b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cAckEnable(pdev);
352b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
3530840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3540840b67ad4db1415094691100441dffe913f76abGreg Hackmann
355c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudovstatic inline void stmI2cInvokeRxCallback(struct I2cStmState *state, size_t tx, size_t rx, int err)
356c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov{
357c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    uint16_t oldTid = osSetCurrentTid(state->tid);
358c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    state->rx.callback(state->rx.cookie, tx, rx, err);
359c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    osSetCurrentTid(oldTid);
360c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov}
361c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov
362c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudovstatic inline void stmI2cInvokeTxCallback(struct I2cStmState *state, size_t tx, size_t rx, int err)
363c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov{
364c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    uint16_t oldTid = osSetCurrentTid(state->tid);
365c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    state->tx.callback(state->tx.cookie, tx, rx, err);
366c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    osSetCurrentTid(oldTid);
367c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov}
368c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov
369b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveRxDone(struct StmI2cDev *pdev)
3700840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
371a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
372a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    size_t rxOffst = state->rx.offset;
3730840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3740840b67ad4db1415094691100441dffe913f76abGreg Hackmann    state->rx.offset = 0;
375c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    stmI2cInvokeRxCallback(state, 0, rxOffst, 0);
3760840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3770840b67ad4db1415094691100441dffe913f76abGreg Hackmann
378b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveTxDone(struct StmI2cDev *pdev)
3790840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
380a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
381a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    size_t txOffst = state->tx.offset;
3820840b67ad4db1415094691100441dffe913f76abGreg Hackmann
383a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cSlaveIdle(pdev);
384c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov    stmI2cInvokeTxCallback(state, txOffst, 0, 0);
385c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
386c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
387b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveTxNextByte(struct StmI2cDev *pdev)
3880840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
389a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
390895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3910840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3929ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    if (state->tx.preamble) {
3939ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        regs->DR = state->tx.byte;
3949ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->tx.offset++;
3959ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    } else if (state->tx.offset < state->tx.size) {
3960840b67ad4db1415094691100441dffe913f76abGreg Hackmann        regs->DR = state->tx.cbuf[state->tx.offset];
3970840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->tx.offset++;
3980840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
3999ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->slaveState = STM_I2C_SLAVE_TX_ARMED;
400b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN);
401c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov        stmI2cInvokeTxCallback(state, state->tx.offset, 0, 0);
4020840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4030840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4040840b67ad4db1415094691100441dffe913f76abGreg Hackmann
405b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveAddrMatched(struct StmI2cDev *pdev)
4060840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
407a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
408895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4090840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4100840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("addr");
4110840b67ad4db1415094691100441dffe913f76abGreg Hackmann
412a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_RX_ARMED) {
413a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_RX;
414b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
415d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann    } else if (state->slaveState == STM_I2C_SLAVE_TX) {
416b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
4170840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
418c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    /* clear ADDR by doing a dummy reads from SR1 (already read) then SR2 */
4190840b67ad4db1415094691100441dffe913f76abGreg Hackmann    (void)regs->SR2;
4200840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4210840b67ad4db1415094691100441dffe913f76abGreg Hackmann
422b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveStopRxed(struct StmI2cDev *pdev)
4230840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
424895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4250840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4260840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("stopf");
4270840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4280840b67ad4db1415094691100441dffe913f76abGreg Hackmann    (void)regs->SR1;
429a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cEnable(pdev);
4300840b67ad4db1415094691100441dffe913f76abGreg Hackmann    /* clear STOPF by doing a dummy read from SR1 and strobing the PE bit */
4310840b67ad4db1415094691100441dffe913f76abGreg Hackmann
432a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cSlaveIdle(pdev);
433b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cSlaveRxDone(pdev);
4340840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4350840b67ad4db1415094691100441dffe913f76abGreg Hackmann
436b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveRxBufNotEmpty(struct StmI2cDev *pdev)
4370840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
438a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
439895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4400840b67ad4db1415094691100441dffe913f76abGreg Hackmann    uint8_t data = regs->DR;
4410840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4420840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("rxne");
4430840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4440840b67ad4db1415094691100441dffe913f76abGreg Hackmann    if (state->rx.offset < state->rx.size) {
4450840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->rx.buf[state->rx.offset] = data;
4460840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->rx.offset++;
4470840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
448b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
4490840b67ad4db1415094691100441dffe913f76abGreg Hackmann        /* TODO: error on overflow */
4500840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4510840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4520840b67ad4db1415094691100441dffe913f76abGreg Hackmann
453b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveTxBufEmpty(struct StmI2cDev *pdev)
4540840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
455a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
4560840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4570840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("txe");
4580840b67ad4db1415094691100441dffe913f76abGreg Hackmann
459a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_RX) {
460a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_TX_ARMED;
461b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN);
462b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
463b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveRxDone(pdev);
464b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        /* stmI2cTxNextByte() will happen when the task provides a
4650840b67ad4db1415094691100441dffe913f76abGreg Hackmann           TX buffer; the I2C controller will stretch the clock until then */
4660840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
467b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveTxNextByte(pdev);
4680840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4690840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4700840b67ad4db1415094691100441dffe913f76abGreg Hackmann
471b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveNakRxed(struct StmI2cDev *pdev)
4720840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
473a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
474895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4750840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4760840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("af");
4770840b67ad4db1415094691100441dffe913f76abGreg Hackmann
478a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_TX) {
479d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        state->tx.offset--;
480d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        /* NACKs seem to be preceded by a spurious TXNE, so adjust the offset to
481d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann           compensate (the corresponding byte written to DR was never actually
482d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann           transmitted) */
483b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveTxDone(pdev);
4840840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4850840b67ad4db1415094691100441dffe913f76abGreg Hackmann    regs->SR1 &= ~I2C_SR1_AF;
4860840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4870840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4881a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cMasterTxRxDone(struct StmI2cDev *pdev, int err)
489b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann{
490b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    struct I2cStmState *state = &pdev->state;
491b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    size_t txOffst = state->tx.offset;
492b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    size_t rxOffst = state->rx.offset;
493b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    uint32_t id;
494b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    int i;
495b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    struct StmI2cXfer *xfer;
496b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
497287671677bb946b266dc4c8fc39582533272363cBen Fennema    if (pdev->board->sleepDev >= 0)
498287671677bb946b266dc4c8fc39582533272363cBen Fennema        platReleaseDevInSleepMode(pdev->board->sleepDev);
499ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema
500b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    state->tx.offset = 0;
501b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    state->rx.offset = 0;
50272638ba906c8825313090d4d4aac66b809659e85Ben Fennema    stmI2cInvokeTxCallback(state, txOffst, rxOffst, err);
503b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
504b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    do {
5058cf410ff3b2d8a09f3aa2b5ca10253732e8e6f78Alexey Polyudov        id = atomicAdd32bits(&pdev->next, 1);
506b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    } while (!id);
507b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
508b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    for (i=0; i<I2C_MAX_QUEUE_DEPTH; i++) {
509b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        xfer = &mXfers[i];
510b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
511b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        if (xfer->busId == (pdev - mStmI2cDevs) &&
512b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                atomicCmpXchg32bits(&xfer->id, id, 0)) {
513b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            pdev->addr = xfer->addr;
514b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.cbuf = xfer->txBuf;
515b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.offset = 0;
516b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.size = xfer->txSize;
517b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.callback = xfer->callback;
518b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.cookie = xfer->cookie;
519b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.buf = xfer->rxBuf;
520b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.offset = 0;
521b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.size = xfer->rxSize;
522b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.callback = NULL;
523b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.cookie = NULL;
524f62fa5ad2731c3f0711eacc4a623ed6cfd3e05beBen Fennema            state->tid = xfer->tid;
525b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            atomicWriteByte(&state->masterState, STM_I2C_MASTER_START);
526287671677bb946b266dc4c8fc39582533272363cBen Fennema            if (pdev->board->sleepDev >= 0)
527287671677bb946b266dc4c8fc39582533272363cBen Fennema                platRequestDevInSleepMode(pdev->board->sleepDev, 12);
528b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cPutXfer(xfer);
5296b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann            stmI2cStartEnable(pdev);
530b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            return;
531b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        }
532b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    }
533b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
534b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE);
535b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann}
536b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
5371a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic void stmI2cMasterDmaTxDone(void *cookie, uint16_t bytesLeft, int err)
5381a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5391a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2cDev *pdev = cookie;
5401a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct I2cStmState *state = &pdev->state;
5411a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
5421a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5431a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.offset = state->tx.size - bytesLeft;
5441a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.size = 0;
5451a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaDisable(pdev);
5461a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    if (err == 0 && state->rx.size > 0) {
5471a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        atomicWriteByte(&state->masterState, STM_I2C_MASTER_START);
5481a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cStartEnable(pdev);
5491a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    } else {
5501a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        while (!(regs->SR1 & I2C_SR1_BTF))
5511a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            ;
5521a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5531a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cStopEnable(pdev);
5541a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterTxRxDone(pdev, err);
5551a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    }
5561a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5571a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5581a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic void stmI2cMasterDmaRxDone(void *cookie, uint16_t bytesLeft, int err)
5591a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5601a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2cDev *pdev = cookie;
5611a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct I2cStmState *state = &pdev->state;
5621a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5631a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->rx.offset = state->rx.size - bytesLeft;
5641a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->rx.size = 0;
5651a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5661a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaDisable(pdev);
5671a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cStopEnable(pdev);
5681a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cMasterTxRxDone(pdev, err);
5691a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5701a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
571102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic inline void stmI2cMasterDmaCancel(struct StmI2cDev *pdev)
572102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
573102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct I2cStmState *state = &pdev->state;
574102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
575102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    dmaStop(I2C_DMA_BUS, pdev->board->dmaRx.stream);
576102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    state->rx.offset = state->rx.size - dmaBytesLeft(I2C_DMA_BUS,
577102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            pdev->board->dmaRx.stream);
578102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    dmaStop(I2C_DMA_BUS, pdev->board->dmaTx.stream);
579102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    state->tx.offset = state->tx.size - dmaBytesLeft(I2C_DMA_BUS,
580102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            pdev->board->dmaTx.stream);
581102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
582102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cDmaDisable(pdev);
583102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
584102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
5851a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cMasterStartDma(struct StmI2cDev *pdev,
5861a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        const struct StmI2cDmaCfg *dmaCfg, const void *buf,
5871a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        size_t size, DmaCallbackF callback, bool rx, bool last)
5881a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5891a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
5901a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct dmaMode mode;
5911a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5921a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    memset(&mode, 0, sizeof(mode));
5931a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.priority = DMA_PRIORITY_HIGH;
5941a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.direction = rx ? DMA_DIRECTION_PERIPH_TO_MEM :
5951a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            DMA_DIRECTION_MEM_TO_PERIPH;
5961a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.periphAddr = (uintptr_t)&regs->DR;
5971a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.minc = true;
5981a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.channel = dmaCfg->channel;
5991a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
6001a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    dmaStart(I2C_DMA_BUS, dmaCfg->stream, buf, size, &mode, callback, pdev);
6011a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    if (last)
6021a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_LAST);
6031a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    else
6041a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_LAST);
6051a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaEnable(pdev);
6061a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
6071a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
608b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterSentStart(struct StmI2cDev *pdev)
6090840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
610a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
611895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
6120840b67ad4db1415094691100441dffe913f76abGreg Hackmann
61381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (atomicReadByte(&state->masterState) == STM_I2C_MASTER_START) {
614c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (state->tx.size > 0) {
61581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            atomicWriteByte(&state->masterState, STM_I2C_MASTER_TX_ADDR);
616c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->DR = pdev->addr << 1;
617c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else {
61881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            atomicWriteByte(&state->masterState, STM_I2C_MASTER_RX_ADDR);
619b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cAckEnable(pdev);
620c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->DR = (pdev->addr << 1) | 0x01;
621c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        }
622c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
6230840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
6240840b67ad4db1415094691100441dffe913f76abGreg Hackmann
625b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterSentAddr(struct StmI2cDev *pdev)
6260840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
627a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
628895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
62981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState = atomicReadByte(&state->masterState);
6300840b67ad4db1415094691100441dffe913f76abGreg Hackmann
63181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (masterState == STM_I2C_MASTER_TX_ADDR) {
6321a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterStartDma(pdev, &pdev->board->dmaTx, state->tx.cbuf,
6331a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->tx.size, stmI2cMasterDmaTxDone, false, !!state->rx.size);
634c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR2; // Clear ADDR
63581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_TX_DATA);
63681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    } else if (masterState == STM_I2C_MASTER_RX_ADDR) {
637c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (state->rx.size == 1) // Generate NACK here for 1 byte transfers
638b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cAckDisable(pdev);
6391a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
6401a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterStartDma(pdev, &pdev->board->dmaRx, state->rx.buf,
6411a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->rx.size, stmI2cMasterDmaRxDone, true,
6421a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->rx.size > 1);
643c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR2; // Clear ADDR
64481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_RX_DATA);
645c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
646c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
647c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
648b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterNakRxed(struct StmI2cDev *pdev)
649c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
650a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
651895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
65281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState = atomicReadByte(&state->masterState);
65372638ba906c8825313090d4d4aac66b809659e85Ben Fennema    int err = 0;
654c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
65581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (masterState == STM_I2C_MASTER_TX_ADDR ||
65672638ba906c8825313090d4d4aac66b809659e85Ben Fennema            masterState == STM_I2C_MASTER_RX_ADDR) {
65772638ba906c8825313090d4d4aac66b809659e85Ben Fennema        err = -ENXIO;
65872638ba906c8825313090d4d4aac66b809659e85Ben Fennema    } else if (masterState == STM_I2C_MASTER_TX_DATA ||
65981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_RX_DATA) {
660102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        stmI2cMasterDmaCancel(pdev);
66172638ba906c8825313090d4d4aac66b809659e85Ben Fennema        err = -EIO;
66272638ba906c8825313090d4d4aac66b809659e85Ben Fennema    }
6631a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
66472638ba906c8825313090d4d4aac66b809659e85Ben Fennema    if (err) {
665c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR1 &= ~I2C_SR1_AF;
666b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cStopEnable(pdev);
66772638ba906c8825313090d4d4aac66b809659e85Ben Fennema        stmI2cMasterTxRxDone(pdev, err);
668c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
669c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
670c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
671102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic void stmI2cMasterBusError(struct StmI2cDev *pdev)
672102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
673102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
674102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
675102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterDmaCancel(pdev);
676102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    regs->SR1 &= ~I2C_SR1_BERR;
67755783a2db53152e98b17ea3252eb814d97b9b9c7Zhengyin Qian    stmI2cMasterTxRxDone(pdev, -EIO);
678102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
679102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
680102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic void stmI2cMasterArbitrationLoss(struct StmI2cDev *pdev)
681102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
682102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
683102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
684102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterDmaCancel(pdev);
685102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    regs->SR1 &= ~I2C_SR1_ARLO;
68655783a2db53152e98b17ea3252eb814d97b9b9c7Zhengyin Qian    stmI2cMasterTxRxDone(pdev, -EBUSY);
687102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
688102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
689102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic void stmI2cMasterUnexpectedError(struct StmI2cDev *pdev)
690102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
691102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
692102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
693102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    osLog(LOG_ERROR, "Unexpected I2C ERR interrupt: SR1 = %04lX, SR2 = %04lX\n",
694102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            regs->SR1, regs->SR2);
695102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
696102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterDmaCancel(pdev);
697102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    regs->SR1 = 0;
69855783a2db53152e98b17ea3252eb814d97b9b9c7Zhengyin Qian    stmI2cMasterTxRxDone(pdev, -EIO);
699102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
700102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
701a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic void stmI2cIsrEvent(struct StmI2cDev *pdev)
702c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
703895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
704c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    uint16_t sr1 = regs->SR1;
705c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
706c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
707c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_ADDR) {
708b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveAddrMatched(pdev);
709c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_RXNE) {
710b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveRxBufNotEmpty(pdev);
711c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_TXE) {
712b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveTxBufEmpty(pdev);
713c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_BTF) {
714c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            if (regs->SR2 & I2C_SR2_TRA)
715b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                stmI2cSlaveTxBufEmpty(pdev);
716c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema           else
717b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                stmI2cSlaveRxBufNotEmpty(pdev);
718d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        } else if (sr1 & I2C_SR1_STOPF) {
719b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveStopRxed(pdev);
720c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        }
721c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        /* TODO: other flags */
722c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (pdev->state.mode == STM_I2C_MASTER) {
723c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_SB)
724b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterSentStart(pdev);
725c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        else if (sr1 & I2C_SR1_ADDR)
726b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterSentAddr(pdev);
727c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
728c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
729c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
730a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic void stmI2cIsrError(struct StmI2cDev *pdev)
731c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
732895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
733c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    uint16_t sr1 = regs->SR1;
734c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
735c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
736c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_AF)
737b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveNakRxed(pdev);
738c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        /* TODO: other flags */
739c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (pdev->state.mode == STM_I2C_MASTER) {
740c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_AF)
741b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterNakRxed(pdev);
742102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        else if (sr1 & I2C_SR1_BERR)
743102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            stmI2cMasterBusError(pdev);
744102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        else if (sr1 & I2C_SR1_ARLO)
745102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            stmI2cMasterArbitrationLoss(pdev);
746102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        else
747102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            stmI2cMasterUnexpectedError(pdev);
748c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
7490840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
7500840b67ad4db1415094691100441dffe913f76abGreg Hackmann
7510840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define DECLARE_IRQ_HANDLERS(_n)                \
7520840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_EV_IRQHandler();      \
7530840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_ER_IRQHandler();      \
7540840b67ad4db1415094691100441dffe913f76abGreg Hackmann                                                \
7550840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_EV_IRQHandler()       \
7560840b67ad4db1415094691100441dffe913f76abGreg Hackmann    {                                           \
757895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cIsrEvent(&mStmI2cDevs[_n - 1]);  \
7580840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }                                           \
7590840b67ad4db1415094691100441dffe913f76abGreg Hackmann                                                \
7600840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_ER_IRQHandler()       \
7610840b67ad4db1415094691100441dffe913f76abGreg Hackmann    {                                           \
762895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cIsrError(&mStmI2cDevs[_n - 1]);  \
7630840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
7640840b67ad4db1415094691100441dffe913f76abGreg Hackmann
765895ed4022a50ee173631b04b791fe13114bcdd55Ben FennemaDECLARE_IRQ_HANDLERS(1);
766f6063e913e1882f4d8767c93b168a7c201ae8b76Antonio BorneoDECLARE_IRQ_HANDLERS(2);
767e0771b85c97ed0a90ff0824530a98f4f69e9b1a9Ben FennemaDECLARE_IRQ_HANDLERS(3);
768895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
76971b642d969783c6514970587e30502db3ba112c3Dmitry Grinbergstatic inline struct Gpio* stmI2cGpioInit(const struct StmI2cBoardCfg *board, const struct StmI2cGpioCfg *cfg)
7700840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
7713568682fec0484260cfe2b9ba0d1540f956c21cbDmitry Grinberg    struct Gpio* gpio = gpioRequest(cfg->gpioNum);
772de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    gpioConfigAlt(gpio, board->gpioSpeed, board->gpioPull, GPIO_OUT_OPEN_DRAIN,
773de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann            cfg->func);
77471b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
77571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg    return gpio;
7760840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
7770840b67ad4db1415094691100441dffe913f76abGreg Hackmann
778342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cMasterRequest(uint32_t busId, uint32_t speed)
7790840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
780895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
7810840b67ad4db1415094691100441dffe913f76abGreg Hackmann        return -EINVAL;
7820840b67ad4db1415094691100441dffe913f76abGreg Hackmann
783de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
784de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    if (!board)
785de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        return -EINVAL;
786de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann
787895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
78881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct I2cStmState *state = &pdev->state;
789895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = &mStmI2cCfgs[busId];
7900840b67ad4db1415094691100441dffe913f76abGreg Hackmann
79181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode == STM_I2C_DISABLED) {
79281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        state->mode = STM_I2C_MASTER;
793895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
794895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pdev->cfg = cfg;
795de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        pdev->board = board;
79681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        pdev->next = 2;
79781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        pdev->last = 1;
79881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicBitsetInit(mXfersValid, I2C_MAX_QUEUE_DEPTH);
799895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
80071b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        pdev->scl = stmI2cGpioInit(board, &board->gpioScl);
80171b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        pdev->sda = stmI2cGpioInit(board, &board->gpioSda);
802c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
803c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, true);
804c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
805a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cDisable(pdev);
806c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
807c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, true);
808c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, false);
8090840b67ad4db1415094691100441dffe913f76abGreg Hackmann
8101a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITEVTEN | I2C_CR2_ITERREN);
811a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cSpeedSet(pdev, speed);
81281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE);
813c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
814895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEr);
815895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEv);
816c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
817a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cEnable(pdev);
818c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
819c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
820c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
821c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
8220840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
8230840b67ad4db1415094691100441dffe913f76abGreg Hackmann
824342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cMasterRelease(uint32_t busId)
8250840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
826895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
827c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
828c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
829895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
83081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct I2cStmState *state = &pdev->state;
831895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
8320840b67ad4db1415094691100441dffe913f76abGreg Hackmann
83381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode == STM_I2C_MASTER) {
834ddcba9d9835dc96c06488f56f55e5835a46eaff3Ben Fennema        if (atomicReadByte(&state->masterState) == STM_I2C_MASTER_IDLE) {
835ddcba9d9835dc96c06488f56f55e5835a46eaff3Ben Fennema            state->mode = STM_I2C_DISABLED;
8361a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            stmI2cIrqEnable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
83781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            stmI2cDisable(pdev);
83881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, false);
83971b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
84071b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg            gpioRelease(pdev->scl);
84171b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg            gpioRelease(pdev->sda);
84271b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
84381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            return 0;
84481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        } else {
84581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            return -EBUSY;
84681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        }
847c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
84881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return -EINVAL;
849c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
850c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
8510840b67ad4db1415094691100441dffe913f76abGreg Hackmann
85281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
853342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cMasterTxRx(uint32_t busId, uint32_t addr,
854895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        const void *txBuf, size_t txSize, void *rxBuf, size_t rxSize,
855895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        I2cCallbackF callback, void *cookie)
856c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
85781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t id;
85881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
859895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
860c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
861c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    else if (addr & 0x80)
862c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -ENXIO;
8630840b67ad4db1415094691100441dffe913f76abGreg Hackmann
864895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
865a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
8660840b67ad4db1415094691100441dffe913f76abGreg Hackmann
86781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode != STM_I2C_MASTER)
86881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return -EINVAL;
869c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
87081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct StmI2cXfer *xfer = stmI2cGetXfer();
87181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
87281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (xfer) {
87381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->busId = busId;
87481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->addr = addr;
87581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->txBuf = txBuf;
87681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->txSize = txSize;
87781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->rxBuf = rxBuf;
87881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->rxSize = rxSize;
87981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->callback = callback;
88081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->cookie = cookie;
881f62fa5ad2731c3f0711eacc4a623ed6cfd3e05beBen Fennema        xfer->tid = osGetCurrentTid();
88281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
88381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        do {
8848cf410ff3b2d8a09f3aa2b5ca10253732e8e6f78Alexey Polyudov            id = atomicAdd32bits(&pdev->last, 1);
88581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        } while (!id);
88681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
88781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // after this point the transfer can be picked up by the transfer
88881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // complete interrupt
88981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWrite32bits(&xfer->id, id);
89081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
89181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // only initiate transfer here if we are in IDLE. Otherwise the transfer
89281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // completion interrupt will start the next transfer (not necessarily
89381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // this one)
89481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        if (atomicCmpXchgByte((uint8_t *)&state->masterState,
89581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                STM_I2C_MASTER_IDLE, STM_I2C_MASTER_START)) {
89681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            // it is possible for this transfer to already be complete by the
89781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            // time we get here. if so, transfer->id will have been set to 0.
89881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            if (atomicCmpXchg32bits(&xfer->id, id, 0)) {
89981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                pdev->addr = xfer->addr;
90081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.cbuf = xfer->txBuf;
90181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.offset = 0;
90281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.size = xfer->txSize;
90381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.callback = xfer->callback;
90481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.cookie = xfer->cookie;
90581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.buf = xfer->rxBuf;
90681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.offset = 0;
90781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.size = xfer->rxSize;
90881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.callback = NULL;
90981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.cookie = NULL;
910f62fa5ad2731c3f0711eacc4a623ed6cfd3e05beBen Fennema                state->tid = xfer->tid;
911287671677bb946b266dc4c8fc39582533272363cBen Fennema                if (pdev->board->sleepDev >= 0)
912287671677bb946b266dc4c8fc39582533272363cBen Fennema                    platRequestDevInSleepMode(pdev->board->sleepDev, 12);
91381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                stmI2cPutXfer(xfer);
9146b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann                stmI2cStartEnable(pdev);
91581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            }
91681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        }
917c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
918c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
919c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
920c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
9210840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
9220840b67ad4db1415094691100441dffe913f76abGreg Hackmann
923342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveRequest(uint32_t busId, uint32_t addr)
9240840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
925895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
926c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
927c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
928de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
929de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    if (!board)
930de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        return -EINVAL;
931de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann
932895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
933895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = &mStmI2cCfgs[busId];
934c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
935c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_DISABLED) {
936c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->state.mode = STM_I2C_SLAVE;
937c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
938c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->addr = addr;
939895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pdev->cfg = cfg;
940de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        pdev->board = board;
9410840b67ad4db1415094691100441dffe913f76abGreg Hackmann
94271b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        pdev->scl = stmI2cGpioInit(board, &board->gpioScl);
94371b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        pdev->sda = stmI2cGpioInit(board, &board->gpioSda);
944c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
945c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
946c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
9470840b67ad4db1415094691100441dffe913f76abGreg Hackmann        return -EBUSY;
948c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
949c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
9500840b67ad4db1415094691100441dffe913f76abGreg Hackmann
951342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveRelease(uint32_t busId)
952c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
953895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
954c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
9550840b67ad4db1415094691100441dffe913f76abGreg Hackmann
956895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
957895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
958a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
959c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
960c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->state.mode = STM_I2C_DISABLED;
9611a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
962b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
963895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cDisable(pdev);
964895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, false);
96571b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
96671b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        gpioRelease(pdev->scl);
96771b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg        gpioRelease(pdev->sda);
96871b642d969783c6514970587e30502db3ba112c3Dmitry Grinberg
969c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
970c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
971c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
972c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
9730840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
974a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
975342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergvoid i2cSlaveEnableRx(uint32_t busId, void *rxBuf, size_t rxSize,
976a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        I2cCallbackF callback, void *cookie)
9770840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
978895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
979895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
980a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
981a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
982c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
983366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg        state->rx.buf = rxBuf;
984c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.offset = 0;
985895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        state->rx.size = rxSize;
986c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.callback = callback;
987c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.cookie = cookie;
988a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_RX_ARMED;
989c36763df4fb478679f842e9dd9bb7a1ae314a60aAlexey Polyudov        state->tid = osGetCurrentTid();
990c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
991c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, true);
992c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, true);
993c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, false);
994c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
995895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEr);
996895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEv);
997c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
998a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cEnable(pdev);
999c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        cfg->regs->OAR1 = I2C_OAR1_ADD7(pdev->addr);
1000b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
1001b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckEnable(pdev);
1002c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
10030840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
1004a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
1005342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergstatic int i2cSlaveTx(uint32_t busId, const void *txBuf, uint8_t byte,
10069ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        size_t txSize, I2cCallbackF callback, void *cookie)
1007c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
1008895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
1009a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
1010c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
1011c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
1012d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        if (state->slaveState == STM_I2C_SLAVE_RX)
1013c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            return -EBUSY;
1014a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
10159ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        if (txBuf) {
10169ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.cbuf = txBuf;
10179ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.preamble = false;
10189ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        } else {
10199ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.byte = byte;
10209ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.preamble = true;
10219ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        }
1022c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.offset = 0;
1023895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        state->tx.size = txSize;
1024c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.callback = callback;
1025c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.cookie = cookie;
1026a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
10279ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        if (state->slaveState == STM_I2C_SLAVE_TX_ARMED) {
10289ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->slaveState = STM_I2C_SLAVE_TX;
1029b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveTxNextByte(pdev);
1030b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN);
1031d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        } else {
1032d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann            state->slaveState = STM_I2C_SLAVE_TX;
10339ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        }
1034c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
1035c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
1036c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
1037c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
1038c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
1039c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
10409ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann
1041342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveTxPreamble(uint32_t busId, uint8_t byte, I2cCallbackF callback,
10429ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        void *cookie)
10439ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann{
10449ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    return i2cSlaveTx(busId, NULL, byte, 0, callback, cookie);
10459ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann}
10469ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann
1047342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveTxPacket(uint32_t busId, const void *txBuf, size_t txSize,
10489ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        I2cCallbackF callback, void *cookie)
10499ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann{
10509ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    return i2cSlaveTx(busId, txBuf, 0, txSize, callback, cookie);
10519ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann}
1052