i2c.c revision 1a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1
10840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <errno.h>
20840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <stdint.h>
31a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann#include <string.h>
40840b67ad4db1415094691100441dffe913f76abGreg Hackmann
50840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <gpio.h>
6a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg#include <i2c.h>
70840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <seos.h>
80840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <util.h>
981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#include <atomicBitset.h>
1081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#include <atomic.h>
110840b67ad4db1415094691100441dffe913f76abGreg Hackmann
120840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <plat/inc/cmsis.h>
131a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann#include <plat/inc/dma.h>
140840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <plat/inc/gpio.h>
15de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann#include <plat/inc/i2c.h>
160840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <plat/inc/pwr.h>
170840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#include <cpu/inc/barrier.h>
1981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
2081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#define I2C_VERBOSE_DEBUG       0
2181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#define I2C_MAX_QUEUE_DEPTH     5
220840b67ad4db1415094691100441dffe913f76abGreg Hackmann
230840b67ad4db1415094691100441dffe913f76abGreg Hackmann#if I2C_VERBOSE_DEBUG
249ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann#define i2c_log_debug(x) osLog(LOG_DEBUG, x "\n")
250840b67ad4db1415094691100441dffe913f76abGreg Hackmann#else
260840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define i2c_log_debug(x) do {} while(0)
270840b67ad4db1415094691100441dffe913f76abGreg Hackmann#endif
280840b67ad4db1415094691100441dffe913f76abGreg Hackmann
290840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_PE          (1 << 0)
300840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SMBUS       (1 << 1)
310840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SMBTYPE     (1 << 3)
320840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENARP       (1 << 4)
330840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENPEC       (1 << 5)
340840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENGC        (1 << 6)
350840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_NOSTRETCH   (1 << 7)
360840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_START       (1 << 8)
370840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_STOP        (1 << 9)
380840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ACK         (1 << 10)
390840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_POS         (1 << 11)
400840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_PEC         (1 << 12)
410840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ALERT       (1 << 13)
420840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SWRST       (1 << 15)
430840b67ad4db1415094691100441dffe913f76abGreg Hackmann
44c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CR2_FREQ(x)     ((x) & I2C_CR2_FREQ_MASK)
450840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_FREQ_MASK   0x3F
460840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITERREN     (1 << 8)
470840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITEVTEN     (1 << 9)
480840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITBUFEN     (1 << 10)
490840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_DMAEN       (1 << 11)
500840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_LAST        (1 << 12)
510840b67ad4db1415094691100441dffe913f76abGreg Hackmann
52c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD7(x)    (((x) & I2C_OAR1_ADD7_MASK) << 1)
53c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD7_MASK  0x7F
54c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD10(x)   ((x) & I2C_OAR1_ADD10_MASK)
55c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD10_MASK 0x3FF
560840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_OAR1_ADDMODE    (1 << 15)
570840b67ad4db1415094691100441dffe913f76abGreg Hackmann
580840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_SB          (1 << 0)
590840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ADDR        (1 << 1)
600840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_BTF         (1 << 2)
610840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ADD10       (1 << 3)
620840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_STOPF       (1 << 4)
630840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_RXNE        (1 << 6)
640840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_TXE         (1 << 7)
650840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_BERR        (1 << 8)
660840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ARLO        (1 << 9)
670840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_AF          (1 << 10)
680840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_OVR         (1 << 11)
690840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_PECERR      (1 << 12)
700840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_TIMEOUT     (1 << 14)
710840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_SMBALERT    (1 << 15)
720840b67ad4db1415094691100441dffe913f76abGreg Hackmann
730840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_MSL         (1 << 0)
740840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_BUSY        (1 << 1)
750840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_TRA         (1 << 2)
760840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_GENCALL     (1 << 4)
770840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_SMBDEFAULT  (1 << 5)
780840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_SMBHOST     (1 << 6)
790840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_DUALF       (1 << 7)
800840b67ad4db1415094691100441dffe913f76abGreg Hackmann
81c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR(x)          ((x) & I2C_CCR_MASK)
82c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_MASK        0xFFF
83c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_DUTY_16_9   (1 << 14)
84c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_FM          (1 << 15)
85c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
86c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_TRISE(x)        ((x) & I2C_TRISE_MASK)
87c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_TRISE_MASK      0x3F
88c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
89a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2c {
900840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CR1;
910840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CR2;
920840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t OAR1;
930840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t OAR2;
940840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t DR;
950840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t SR1;
960840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t SR2;
970840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CCR;
980840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t TRISE;
990840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t FLTR;
1000840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1010840b67ad4db1415094691100441dffe913f76abGreg Hackmann
10281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemaenum StmI2cSpiMasterState
10381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
10481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_IDLE,
10581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_START,
10681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_TX_ADDR,
10781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_TX_DATA,
10881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_RX_ADDR,
10981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_RX_DATA,
11081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
11181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
112a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct I2cStmState {
1130840b67ad4db1415094691100441dffe913f76abGreg Hackmann    struct {
1140840b67ad4db1415094691100441dffe913f76abGreg Hackmann        union {
1150840b67ad4db1415094691100441dffe913f76abGreg Hackmann            uint8_t *buf;
1160840b67ad4db1415094691100441dffe913f76abGreg Hackmann            const uint8_t *cbuf;
1179ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            uint8_t byte;
1180840b67ad4db1415094691100441dffe913f76abGreg Hackmann        };
1190840b67ad4db1415094691100441dffe913f76abGreg Hackmann        size_t size;
1200840b67ad4db1415094691100441dffe913f76abGreg Hackmann        size_t offset;
1219ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        bool preamble;
1220840b67ad4db1415094691100441dffe913f76abGreg Hackmann
123a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        I2cCallbackF callback;
1240840b67ad4db1415094691100441dffe913f76abGreg Hackmann        void *cookie;
1250840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } rx, tx;
1260840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1270840b67ad4db1415094691100441dffe913f76abGreg Hackmann    enum {
128c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_DISABLED,
129c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_SLAVE,
130c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_MASTER,
131c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } mode;
132c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
133c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    enum {
134c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_SLAVE_IDLE,
1350840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_RX_ARMED,
1360840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_RX,
1370840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_TX_ARMED,
1380840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_TX,
139a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    } slaveState;
140c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
14181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    // StmI2cSpiMasterState
14281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState;
1430840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1440840b67ad4db1415094691100441dffe913f76abGreg Hackmann
145a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2cCfg {
146a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct StmI2c *regs;
1470840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1480840b67ad4db1415094691100441dffe913f76abGreg Hackmann    uint32_t clock;
1490840b67ad4db1415094691100441dffe913f76abGreg Hackmann
150895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    IRQn_Type irqEv;
151895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    IRQn_Type irqEr;
1520840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1530840b67ad4db1415094691100441dffe913f76abGreg Hackmann
154a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2cDev {
155895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg;
156de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board;
157a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState state;
1580840b67ad4db1415094691100441dffe913f76abGreg Hackmann
15981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t next;
16081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t last;
16181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
162a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    I2cAddr addr;
1630840b67ad4db1415094691100441dffe913f76abGreg Hackmann
164366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg    struct Gpio scl;
165366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg    struct Gpio sda;
1660840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1670840b67ad4db1415094691100441dffe913f76abGreg Hackmann
16881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic const struct StmI2cCfg mStmI2cCfgs[] = {
16981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [0] = {
17081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C1_BASE,
17181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
17281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C1,
17381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
17481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C1_EV_IRQn,
17581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C1_ER_IRQn,
17681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
17781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [1] = {
17881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C2_BASE,
17981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
18081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C2,
18181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
18281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C2_EV_IRQn,
18381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C2_ER_IRQn,
18481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
18581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [2] = {
18681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C3_BASE,
18781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
18881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C3,
18981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C3_EV_IRQn,
19181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C3_ER_IRQn,
19281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
19381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
19481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic struct StmI2cDev mStmI2cDevs[ARRAY_SIZE(mStmI2cCfgs)];
19681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastruct StmI2cXfer
19881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
19981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t        id;
20081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    const void     *txBuf;
20181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    size_t          txSize;
20281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    void           *rxBuf;
20381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    size_t          rxSize;
20481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    I2cCallbackF    callback;
20581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    void           *cookie;
20681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    I2cBus          busId;
20781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    I2cAddr         addr;
20881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
20981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21081be7381e3399a0ff4c54222987ab7bd0b1169dfBen FennemaATOMIC_BITSET_DECL(mXfersValid, I2C_MAX_QUEUE_DEPTH, static);
21181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic struct StmI2cXfer mXfers[I2C_MAX_QUEUE_DEPTH] = { };
21281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic inline struct StmI2cXfer *stmI2cGetXfer(void)
21481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
21581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    int32_t idx = atomicBitsetFindClearAndSet(mXfersValid);
21681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (idx < 0)
21881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return NULL;
21981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    else
22081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return mXfers + idx;
22181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema}
22281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
22381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic inline void stmI2cPutXfer(struct StmI2cXfer *xfer)
22481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
22581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (xfer)
22681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicBitsetClearBit(mXfersValid, xfer - mXfers);
22781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema}
22881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
229b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cAckEnable(struct StmI2cDev *pdev)
2300840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
231895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 |= I2C_CR1_ACK;
2320840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2330840b67ad4db1415094691100441dffe913f76abGreg Hackmann
234b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cAckDisable(struct StmI2cDev *pdev)
2350840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
236895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 &= ~I2C_CR1_ACK;
2370840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2380840b67ad4db1415094691100441dffe913f76abGreg Hackmann
2391a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cDmaEnable(struct StmI2cDev *pdev)
2401a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
2411a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    pdev->cfg->regs->CR2 |= I2C_CR2_DMAEN;
2421a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
2431a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
2441a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cDmaDisable(struct StmI2cDev *pdev)
2451a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
2461a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    pdev->cfg->regs->CR2 &= ~I2C_CR2_DMAEN;
2471a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
2481a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
249b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cStopEnable(struct StmI2cDev *pdev)
250c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
2516b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
2526b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2536b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    while (regs->CR1 & (I2C_CR1_STOP | I2C_CR1_START))
2546b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann        ;
2556b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    regs->CR1 |= I2C_CR1_STOP;
2566b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann}
2576b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2586b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmannstatic inline void stmI2cStartEnable(struct StmI2cDev *pdev)
2596b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann{
2606b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
2616b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2626b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    while (regs->CR1 & (I2C_CR1_STOP | I2C_CR1_START))
2636b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann        ;
2646b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    regs->CR1 |= I2C_CR1_START;
265c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
266c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
267b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cIrqEnable(struct StmI2cDev *pdev,
2680840b67ad4db1415094691100441dffe913f76abGreg Hackmann        uint32_t mask)
2690840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
270895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR2 |= mask;
2710840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2720840b67ad4db1415094691100441dffe913f76abGreg Hackmann
273b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cIrqDisable(struct StmI2cDev *pdev,
2740840b67ad4db1415094691100441dffe913f76abGreg Hackmann        uint32_t mask)
2750840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
276895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR2 &= ~mask;
2770840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2780840b67ad4db1415094691100441dffe913f76abGreg Hackmann
279a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cEnable(struct StmI2cDev *pdev)
2800840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
281895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 |= I2C_CR1_PE;
2820840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2830840b67ad4db1415094691100441dffe913f76abGreg Hackmann
284a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cDisable(struct StmI2cDev *pdev)
2850840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
286895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 &= ~I2C_CR1_PE;
2870840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2880840b67ad4db1415094691100441dffe913f76abGreg Hackmann
289a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cSpeedSet(struct StmI2cDev *pdev,
290a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        const I2cSpeed speed)
291c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
292895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
293c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    int ccr, ccr_1, ccr_2;
294c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    int apb1_clk;
295c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
296c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    apb1_clk = pwrGetBusSpeed(PERIPH_BUS_APB1);
297c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
298c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    regs->CR2 = (regs->CR2 & ~I2C_CR2_FREQ_MASK) |
299c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema                 I2C_CR2_FREQ(apb1_clk / 1000000);
300c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
301c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (speed <= 100000) {
302c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr = apb1_clk / (speed * 2);
303c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr < 4)
304c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr = 4;
305c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->CCR = I2C_CCR(ccr);
306c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
307c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->TRISE = I2C_TRISE((apb1_clk / 1000000) + 1);
308c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (speed <= 400000) {
309c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr_1 = apb1_clk / (speed * 3);
310c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr_1 == 0 || apb1_clk / (ccr_1 * 3) > speed)
311c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr_1 ++;
312c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr_2 = apb1_clk / (speed * 25);
313c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr_2 == 0 || apb1_clk / (ccr_2 * 25) > speed)
314c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr_2 ++;
315c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
316c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if ((apb1_clk / (ccr_1 * 3)) > (apb1_clk / (ccr_2 * 25)))
317c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->CCR = I2C_CCR_FM | I2C_CCR(ccr_1);
318c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        else
319c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->CCR = I2C_CCR_FM | I2C_CCR_DUTY_16_9 | I2C_CCR(ccr_2);
320c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
321c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->TRISE = I2C_TRISE(((3*apb1_clk)/10000000) + 1);
322c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
323c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
324c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
325a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cSlaveIdle(struct StmI2cDev *pdev)
3260840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
327a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
3280840b67ad4db1415094691100441dffe913f76abGreg Hackmann
329a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    state->slaveState = STM_I2C_SLAVE_RX_ARMED;
330b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cAckEnable(pdev);
331b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
3320840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3330840b67ad4db1415094691100441dffe913f76abGreg Hackmann
334b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveRxDone(struct StmI2cDev *pdev)
3350840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
336a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
337a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    size_t rxOffst = state->rx.offset;
3380840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3390840b67ad4db1415094691100441dffe913f76abGreg Hackmann    state->rx.offset = 0;
34062a051ff2d95252651580d9653b391bf94e756fbGreg Hackmann    state->rx.callback(state->rx.cookie, 0, rxOffst, 0);
3410840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3420840b67ad4db1415094691100441dffe913f76abGreg Hackmann
343b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveTxDone(struct StmI2cDev *pdev)
3440840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
345a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
346a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    size_t txOffst = state->tx.offset;
3470840b67ad4db1415094691100441dffe913f76abGreg Hackmann
348a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cSlaveIdle(pdev);
34962a051ff2d95252651580d9653b391bf94e756fbGreg Hackmann    state->tx.callback(state->tx.cookie, txOffst, 0, 0);
350c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
351c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
352b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveTxNextByte(struct StmI2cDev *pdev)
3530840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
354a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
355895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3560840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3579ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    if (state->tx.preamble) {
3589ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        regs->DR = state->tx.byte;
3599ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->tx.offset++;
3609ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    } else if (state->tx.offset < state->tx.size) {
3610840b67ad4db1415094691100441dffe913f76abGreg Hackmann        regs->DR = state->tx.cbuf[state->tx.offset];
3620840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->tx.offset++;
3630840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
3649ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->slaveState = STM_I2C_SLAVE_TX_ARMED;
365b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN);
3669ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->tx.callback(state->tx.cookie, state->tx.offset, 0, 0);
3670840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
3680840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3690840b67ad4db1415094691100441dffe913f76abGreg Hackmann
370b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveAddrMatched(struct StmI2cDev *pdev)
3710840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
372a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
373895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3740840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3750840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("addr");
3760840b67ad4db1415094691100441dffe913f76abGreg Hackmann
377a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_RX_ARMED) {
378a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_RX;
379b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
380d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann    } else if (state->slaveState == STM_I2C_SLAVE_TX) {
381b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
3820840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
383c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    /* clear ADDR by doing a dummy reads from SR1 (already read) then SR2 */
3840840b67ad4db1415094691100441dffe913f76abGreg Hackmann    (void)regs->SR2;
3850840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3860840b67ad4db1415094691100441dffe913f76abGreg Hackmann
387b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveStopRxed(struct StmI2cDev *pdev)
3880840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
389895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3900840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3910840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("stopf");
3920840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3930840b67ad4db1415094691100441dffe913f76abGreg Hackmann    (void)regs->SR1;
394a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cEnable(pdev);
3950840b67ad4db1415094691100441dffe913f76abGreg Hackmann    /* clear STOPF by doing a dummy read from SR1 and strobing the PE bit */
3960840b67ad4db1415094691100441dffe913f76abGreg Hackmann
397a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cSlaveIdle(pdev);
398b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cSlaveRxDone(pdev);
3990840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4000840b67ad4db1415094691100441dffe913f76abGreg Hackmann
401b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveRxBufNotEmpty(struct StmI2cDev *pdev)
4020840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
403a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
404895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4050840b67ad4db1415094691100441dffe913f76abGreg Hackmann    uint8_t data = regs->DR;
4060840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4070840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("rxne");
4080840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4090840b67ad4db1415094691100441dffe913f76abGreg Hackmann    if (state->rx.offset < state->rx.size) {
4100840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->rx.buf[state->rx.offset] = data;
4110840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->rx.offset++;
4120840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
413b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
4140840b67ad4db1415094691100441dffe913f76abGreg Hackmann        /* TODO: error on overflow */
4150840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4160840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4170840b67ad4db1415094691100441dffe913f76abGreg Hackmann
418b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveTxBufEmpty(struct StmI2cDev *pdev)
4190840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
420a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
4210840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4220840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("txe");
4230840b67ad4db1415094691100441dffe913f76abGreg Hackmann
424a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_RX) {
425a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_TX_ARMED;
426b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN);
427b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
428b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveRxDone(pdev);
429b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        /* stmI2cTxNextByte() will happen when the task provides a
4300840b67ad4db1415094691100441dffe913f76abGreg Hackmann           TX buffer; the I2C controller will stretch the clock until then */
4310840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
432b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveTxNextByte(pdev);
4330840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4340840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4350840b67ad4db1415094691100441dffe913f76abGreg Hackmann
436b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveNakRxed(struct StmI2cDev *pdev)
4370840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
438a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
439895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4400840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4410840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("af");
4420840b67ad4db1415094691100441dffe913f76abGreg Hackmann
443a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_TX) {
444d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        state->tx.offset--;
445d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        /* NACKs seem to be preceded by a spurious TXNE, so adjust the offset to
446d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann           compensate (the corresponding byte written to DR was never actually
447d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann           transmitted) */
448b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveTxDone(pdev);
4490840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4500840b67ad4db1415094691100441dffe913f76abGreg Hackmann    regs->SR1 &= ~I2C_SR1_AF;
4510840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4520840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4531a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cMasterTxRxDone(struct StmI2cDev *pdev, int err)
454b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann{
455b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    struct I2cStmState *state = &pdev->state;
456b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    size_t txOffst = state->tx.offset;
457b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    size_t rxOffst = state->rx.offset;
458b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    uint32_t id;
459b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    int i;
460b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    struct StmI2cXfer *xfer;
461b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
462b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    state->tx.offset = 0;
463b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    state->rx.offset = 0;
4641a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.callback(state->tx.cookie, txOffst, rxOffst, err);
465b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
466b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    do {
467b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        id = atomicAdd(&pdev->next, 1);
468b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    } while (!id);
469b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
470b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    for (i=0; i<I2C_MAX_QUEUE_DEPTH; i++) {
471b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        xfer = &mXfers[i];
472b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
473b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        if (xfer->busId == (pdev - mStmI2cDevs) &&
474b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                atomicCmpXchg32bits(&xfer->id, id, 0)) {
475b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            pdev->addr = xfer->addr;
476b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.cbuf = xfer->txBuf;
477b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.offset = 0;
478b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.size = xfer->txSize;
479b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.callback = xfer->callback;
480b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.cookie = xfer->cookie;
481b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.buf = xfer->rxBuf;
482b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.offset = 0;
483b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.size = xfer->rxSize;
484b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.callback = NULL;
485b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.cookie = NULL;
486b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            atomicWriteByte(&state->masterState, STM_I2C_MASTER_START);
487b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cPutXfer(xfer);
4886b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann            stmI2cStartEnable(pdev);
489b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            return;
490b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        }
491b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    }
492b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
493b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE);
494b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann}
495b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
4961a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic void stmI2cMasterDmaTxDone(void *cookie, uint16_t bytesLeft, int err)
4971a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
4981a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2cDev *pdev = cookie;
4991a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct I2cStmState *state = &pdev->state;
5001a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
5011a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5021a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.offset = state->tx.size - bytesLeft;
5031a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.size = 0;
5041a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaDisable(pdev);
5051a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    if (err == 0 && state->rx.size > 0) {
5061a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        atomicWriteByte(&state->masterState, STM_I2C_MASTER_START);
5071a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cStartEnable(pdev);
5081a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    } else {
5091a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        while (!(regs->SR1 & I2C_SR1_BTF))
5101a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            ;
5111a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5121a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cStopEnable(pdev);
5131a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterTxRxDone(pdev, err);
5141a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    }
5151a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5161a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5171a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic void stmI2cMasterDmaRxDone(void *cookie, uint16_t bytesLeft, int err)
5181a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5191a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2cDev *pdev = cookie;
5201a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct I2cStmState *state = &pdev->state;
5211a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5221a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->rx.offset = state->rx.size - bytesLeft;
5231a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->rx.size = 0;
5241a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5251a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaDisable(pdev);
5261a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cStopEnable(pdev);
5271a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cMasterTxRxDone(pdev, err);
5281a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5291a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5301a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cMasterStartDma(struct StmI2cDev *pdev,
5311a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        const struct StmI2cDmaCfg *dmaCfg, const void *buf,
5321a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        size_t size, DmaCallbackF callback, bool rx, bool last)
5331a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5341a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
5351a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct dmaMode mode;
5361a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5371a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    memset(&mode, 0, sizeof(mode));
5381a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.priority = DMA_PRIORITY_HIGH;
5391a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.direction = rx ? DMA_DIRECTION_PERIPH_TO_MEM :
5401a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            DMA_DIRECTION_MEM_TO_PERIPH;
5411a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.periphAddr = (uintptr_t)&regs->DR;
5421a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.minc = true;
5431a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.channel = dmaCfg->channel;
5441a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5451a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    dmaStart(I2C_DMA_BUS, dmaCfg->stream, buf, size, &mode, callback, pdev);
5461a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    if (last)
5471a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_LAST);
5481a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    else
5491a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_LAST);
5501a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaEnable(pdev);
5511a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5521a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
553b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterSentStart(struct StmI2cDev *pdev)
5540840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
555a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
556895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
5570840b67ad4db1415094691100441dffe913f76abGreg Hackmann
55881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (atomicReadByte(&state->masterState) == STM_I2C_MASTER_START) {
559c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (state->tx.size > 0) {
56081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            atomicWriteByte(&state->masterState, STM_I2C_MASTER_TX_ADDR);
561c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->DR = pdev->addr << 1;
562c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else {
56381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            atomicWriteByte(&state->masterState, STM_I2C_MASTER_RX_ADDR);
564b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cAckEnable(pdev);
565c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->DR = (pdev->addr << 1) | 0x01;
566c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        }
567c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
5680840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
5690840b67ad4db1415094691100441dffe913f76abGreg Hackmann
570b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterSentAddr(struct StmI2cDev *pdev)
5710840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
572a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
573895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
57481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState = atomicReadByte(&state->masterState);
5750840b67ad4db1415094691100441dffe913f76abGreg Hackmann
57681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (masterState == STM_I2C_MASTER_TX_ADDR) {
5771a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterStartDma(pdev, &pdev->board->dmaTx, state->tx.cbuf,
5781a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->tx.size, stmI2cMasterDmaTxDone, false, !!state->rx.size);
579c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR2; // Clear ADDR
58081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_TX_DATA);
58181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    } else if (masterState == STM_I2C_MASTER_RX_ADDR) {
582c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (state->rx.size == 1) // Generate NACK here for 1 byte transfers
583b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cAckDisable(pdev);
5841a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5851a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterStartDma(pdev, &pdev->board->dmaRx, state->rx.buf,
5861a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->rx.size, stmI2cMasterDmaRxDone, true,
5871a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->rx.size > 1);
588c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR2; // Clear ADDR
58981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_RX_DATA);
590c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
591c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
592c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
593b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterNakRxed(struct StmI2cDev *pdev)
594c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
595a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
596895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
59781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState = atomicReadByte(&state->masterState);
598c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
59981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (masterState == STM_I2C_MASTER_TX_ADDR ||
60081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_TX_DATA ||
60181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_RX_ADDR ||
60281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_RX_DATA) {
6031a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        dmaStop(I2C_DMA_BUS, pdev->board->dmaRx.stream);
6041a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        state->rx.offset = state->rx.size - dmaBytesLeft(I2C_DMA_BUS,
6051a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                pdev->board->dmaRx.stream);
6061a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        dmaStop(I2C_DMA_BUS, pdev->board->dmaTx.stream);
6071a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        state->tx.offset = state->tx.size - dmaBytesLeft(I2C_DMA_BUS,
6081a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                pdev->board->dmaTx.stream);
6091a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cDmaDisable(pdev);
6101a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
611c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR1 &= ~I2C_SR1_AF;
612b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cStopEnable(pdev);
6131a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterTxRxDone(pdev, 0);
614c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
615c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
616c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
617a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic void stmI2cIsrEvent(struct StmI2cDev *pdev)
618c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
619895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
620c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    uint16_t sr1 = regs->SR1;
621c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
622c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
623c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_ADDR) {
624b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveAddrMatched(pdev);
625c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_RXNE) {
626b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveRxBufNotEmpty(pdev);
627c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_TXE) {
628b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveTxBufEmpty(pdev);
629c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_BTF) {
630c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            if (regs->SR2 & I2C_SR2_TRA)
631b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                stmI2cSlaveTxBufEmpty(pdev);
632c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema           else
633b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                stmI2cSlaveRxBufNotEmpty(pdev);
634d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        } else if (sr1 & I2C_SR1_STOPF) {
635b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveStopRxed(pdev);
636c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        }
637c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        /* TODO: other flags */
638c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (pdev->state.mode == STM_I2C_MASTER) {
639c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_SB)
640b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterSentStart(pdev);
641c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        else if (sr1 & I2C_SR1_ADDR)
642b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterSentAddr(pdev);
643c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
644c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
645c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
646a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic void stmI2cIsrError(struct StmI2cDev *pdev)
647c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
648895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
649c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    uint16_t sr1 = regs->SR1;
650c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
651c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
652c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_AF)
653b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveNakRxed(pdev);
654c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        /* TODO: other flags */
655c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (pdev->state.mode == STM_I2C_MASTER) {
656c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_AF)
657b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterNakRxed(pdev);
658c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
6590840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
6600840b67ad4db1415094691100441dffe913f76abGreg Hackmann
6610840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define DECLARE_IRQ_HANDLERS(_n)                \
6620840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_EV_IRQHandler();      \
6630840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_ER_IRQHandler();      \
6640840b67ad4db1415094691100441dffe913f76abGreg Hackmann                                                \
6650840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_EV_IRQHandler()       \
6660840b67ad4db1415094691100441dffe913f76abGreg Hackmann    {                                           \
667895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cIsrEvent(&mStmI2cDevs[_n - 1]);  \
6680840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }                                           \
6690840b67ad4db1415094691100441dffe913f76abGreg Hackmann                                                \
6700840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_ER_IRQHandler()       \
6710840b67ad4db1415094691100441dffe913f76abGreg Hackmann    {                                           \
672895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cIsrError(&mStmI2cDevs[_n - 1]);  \
6730840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
6740840b67ad4db1415094691100441dffe913f76abGreg Hackmann
675895ed4022a50ee173631b04b791fe13114bcdd55Ben FennemaDECLARE_IRQ_HANDLERS(1);
676e0771b85c97ed0a90ff0824530a98f4f69e9b1a9Ben FennemaDECLARE_IRQ_HANDLERS(3);
677895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
678de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmannstatic inline void stmI2cGpioInit(struct Gpio *gpio,
679de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        const struct StmI2cBoardCfg *board, const struct StmI2cGpioCfg *cfg)
6800840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
681de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    gpioRequest(gpio, cfg->num);
682de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    gpioConfigAlt(gpio, board->gpioSpeed, board->gpioPull, GPIO_OUT_OPEN_DRAIN,
683de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann            cfg->func);
6840840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
6850840b67ad4db1415094691100441dffe913f76abGreg Hackmann
686895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennemaint i2cMasterRequest(I2cBus busId, I2cSpeed speed)
6870840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
688895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
6890840b67ad4db1415094691100441dffe913f76abGreg Hackmann        return -EINVAL;
6900840b67ad4db1415094691100441dffe913f76abGreg Hackmann
691de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
692de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    if (!board)
693de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        return -EINVAL;
694de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann
695895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
69681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct I2cStmState *state = &pdev->state;
697895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = &mStmI2cCfgs[busId];
6980840b67ad4db1415094691100441dffe913f76abGreg Hackmann
69981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode == STM_I2C_DISABLED) {
70081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        state->mode = STM_I2C_MASTER;
701895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
702895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pdev->cfg = cfg;
703de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        pdev->board = board;
70481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        pdev->next = 2;
70581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        pdev->last = 1;
70681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicBitsetInit(mXfersValid, I2C_MAX_QUEUE_DEPTH);
707895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
708de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->scl, board, &board->gpioScl);
709de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->sda, board, &board->gpioSda);
710c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
711c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, true);
712c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
713a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cDisable(pdev);
714c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
715c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, true);
716c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, false);
7170840b67ad4db1415094691100441dffe913f76abGreg Hackmann
7181a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITEVTEN | I2C_CR2_ITERREN);
719a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cSpeedSet(pdev, speed);
72081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE);
721c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
722895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEr);
723895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEv);
724c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
725a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cEnable(pdev);
726c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
727c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
728c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
729c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
7300840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
7310840b67ad4db1415094691100441dffe913f76abGreg Hackmann
732895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennemaint i2cMasterRelease(I2cBus busId)
7330840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
734895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
735c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
736c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
737895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
73881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct I2cStmState *state = &pdev->state;
739895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
7400840b67ad4db1415094691100441dffe913f76abGreg Hackmann
74181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode == STM_I2C_MASTER) {
742ddcba9d9835dc96c06488f56f55e5835a46eaff3Ben Fennema        if (atomicReadByte(&state->masterState) == STM_I2C_MASTER_IDLE) {
743ddcba9d9835dc96c06488f56f55e5835a46eaff3Ben Fennema            state->mode = STM_I2C_DISABLED;
7441a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            stmI2cIrqEnable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
74581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            stmI2cDisable(pdev);
74681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, false);
74781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            return 0;
74881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        } else {
74981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            return -EBUSY;
75081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        }
751c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
75281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return -EINVAL;
753c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
754c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
7550840b67ad4db1415094691100441dffe913f76abGreg Hackmann
75681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
757895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennemaint i2cMasterTxRx(I2cBus busId, I2cAddr addr,
758895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        const void *txBuf, size_t txSize, void *rxBuf, size_t rxSize,
759895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        I2cCallbackF callback, void *cookie)
760c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
76181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t id;
76281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
763895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
764c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
765c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    else if (addr & 0x80)
766c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -ENXIO;
7670840b67ad4db1415094691100441dffe913f76abGreg Hackmann
768895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
769a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
7700840b67ad4db1415094691100441dffe913f76abGreg Hackmann
77181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode != STM_I2C_MASTER)
77281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return -EINVAL;
773c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
77481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct StmI2cXfer *xfer = stmI2cGetXfer();
77581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
77681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (xfer) {
77781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->busId = busId;
77881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->addr = addr;
77981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->txBuf = txBuf;
78081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->txSize = txSize;
78181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->rxBuf = rxBuf;
78281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->rxSize = rxSize;
78381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->callback = callback;
78481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->cookie = cookie;
78581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
78681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        do {
78781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            id = atomicAdd(&pdev->last, 1);
78881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        } while (!id);
78981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
79081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // after this point the transfer can be picked up by the transfer
79181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // complete interrupt
79281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWrite32bits(&xfer->id, id);
79381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
79481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // only initiate transfer here if we are in IDLE. Otherwise the transfer
79581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // completion interrupt will start the next transfer (not necessarily
79681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // this one)
79781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        if (atomicCmpXchgByte((uint8_t *)&state->masterState,
79881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                STM_I2C_MASTER_IDLE, STM_I2C_MASTER_START)) {
79981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            // it is possible for this transfer to already be complete by the
80081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            // time we get here. if so, transfer->id will have been set to 0.
80181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            if (atomicCmpXchg32bits(&xfer->id, id, 0)) {
80281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                pdev->addr = xfer->addr;
80381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.cbuf = xfer->txBuf;
80481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.offset = 0;
80581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.size = xfer->txSize;
80681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.callback = xfer->callback;
80781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.cookie = xfer->cookie;
80881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.buf = xfer->rxBuf;
80981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.offset = 0;
81081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.size = xfer->rxSize;
81181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.callback = NULL;
81281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.cookie = NULL;
81381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                stmI2cPutXfer(xfer);
8146b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann                stmI2cStartEnable(pdev);
81581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            }
81681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        }
817c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
818c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
819c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
820c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
8210840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
8220840b67ad4db1415094691100441dffe913f76abGreg Hackmann
823895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennemaint i2cSlaveRequest(I2cBus busId, I2cAddr addr)
8240840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
825895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
826c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
827c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
828de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
829de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    if (!board)
830de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        return -EINVAL;
831de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann
832895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
833895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = &mStmI2cCfgs[busId];
834c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
835c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_DISABLED) {
836c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->state.mode = STM_I2C_SLAVE;
837c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
838c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->addr = addr;
839895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pdev->cfg = cfg;
840de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        pdev->board = board;
8410840b67ad4db1415094691100441dffe913f76abGreg Hackmann
842de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->scl, board, &board->gpioScl);
843de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->sda, board, &board->gpioSda);
844c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
845c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
846c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
8470840b67ad4db1415094691100441dffe913f76abGreg Hackmann        return -EBUSY;
848c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
849c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
8500840b67ad4db1415094691100441dffe913f76abGreg Hackmann
851895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennemaint i2cSlaveRelease(I2cBus busId)
852c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
853895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
854c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
8550840b67ad4db1415094691100441dffe913f76abGreg Hackmann
856895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
857895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
858a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
859c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
860c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->state.mode = STM_I2C_DISABLED;
8611a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
862b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
863895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cDisable(pdev);
864895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, false);
865c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
866c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
867c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
868c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
8690840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
870a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
871895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennemavoid i2cSlaveEnableRx(I2cBus busId, void *rxBuf, size_t rxSize,
872a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        I2cCallbackF callback, void *cookie)
8730840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
874895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
875895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
876a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
877a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
878c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
879366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg        state->rx.buf = rxBuf;
880c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.offset = 0;
881895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        state->rx.size = rxSize;
882c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.callback = callback;
883c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.cookie = cookie;
884a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_RX_ARMED;
885c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
886c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, true);
887c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, true);
888c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, false);
889c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
890895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEr);
891895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEv);
892c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
893a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cEnable(pdev);
894c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        cfg->regs->OAR1 = I2C_OAR1_ADD7(pdev->addr);
895b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
896b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckEnable(pdev);
897c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
8980840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
899a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
9009ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmannstatic int i2cSlaveTx(I2cBus busId, const void *txBuf, uint8_t byte,
9019ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        size_t txSize, I2cCallbackF callback, void *cookie)
902c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
903895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
904a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
905c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
906c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
907d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        if (state->slaveState == STM_I2C_SLAVE_RX)
908c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            return -EBUSY;
909a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
9109ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        if (txBuf) {
9119ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.cbuf = txBuf;
9129ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.preamble = false;
9139ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        } else {
9149ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.byte = byte;
9159ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.preamble = true;
9169ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        }
917c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.offset = 0;
918895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        state->tx.size = txSize;
919c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.callback = callback;
920c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.cookie = cookie;
921a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
9229ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        if (state->slaveState == STM_I2C_SLAVE_TX_ARMED) {
9239ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->slaveState = STM_I2C_SLAVE_TX;
924b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveTxNextByte(pdev);
925b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN);
926d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        } else {
927d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann            state->slaveState = STM_I2C_SLAVE_TX;
9289ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        }
929c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
930c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
931c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
932c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
933c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
934c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
9359ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann
9369ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmannint i2cSlaveTxPreamble(I2cBus busId, uint8_t byte, I2cCallbackF callback,
9379ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        void *cookie)
9389ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann{
9399ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    return i2cSlaveTx(busId, NULL, byte, 0, callback, cookie);
9409ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann}
9419ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann
9429ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmannint i2cSlaveTxPacket(I2cBus busId, const void *txBuf, size_t txSize,
9439ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        I2cCallbackF callback, void *cookie)
9449ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann{
9459ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    return i2cSlaveTx(busId, txBuf, 0, txSize, callback, cookie);
9469ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann}
947