i2c.c revision 342c37806ad0ac7d1e5d3f5dff74065d28e5ec3f
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>
11ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema#include <platform.h>
120840b67ad4db1415094691100441dffe913f76abGreg Hackmann
130840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <plat/inc/cmsis.h>
141a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann#include <plat/inc/dma.h>
150840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <plat/inc/gpio.h>
16de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann#include <plat/inc/i2c.h>
170840b67ad4db1415094691100441dffe913f76abGreg Hackmann#include <plat/inc/pwr.h>
18ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema#include <plat/inc/plat.h>
190840b67ad4db1415094691100441dffe913f76abGreg Hackmann
2081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#include <cpu/inc/barrier.h>
2181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
2281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#define I2C_VERBOSE_DEBUG       0
2381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema#define I2C_MAX_QUEUE_DEPTH     5
240840b67ad4db1415094691100441dffe913f76abGreg Hackmann
250840b67ad4db1415094691100441dffe913f76abGreg Hackmann#if I2C_VERBOSE_DEBUG
269ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann#define i2c_log_debug(x) osLog(LOG_DEBUG, x "\n")
270840b67ad4db1415094691100441dffe913f76abGreg Hackmann#else
280840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define i2c_log_debug(x) do {} while(0)
290840b67ad4db1415094691100441dffe913f76abGreg Hackmann#endif
300840b67ad4db1415094691100441dffe913f76abGreg Hackmann
310840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_PE          (1 << 0)
320840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SMBUS       (1 << 1)
330840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SMBTYPE     (1 << 3)
340840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENARP       (1 << 4)
350840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENPEC       (1 << 5)
360840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ENGC        (1 << 6)
370840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_NOSTRETCH   (1 << 7)
380840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_START       (1 << 8)
390840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_STOP        (1 << 9)
400840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ACK         (1 << 10)
410840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_POS         (1 << 11)
420840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_PEC         (1 << 12)
430840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_ALERT       (1 << 13)
440840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR1_SWRST       (1 << 15)
450840b67ad4db1415094691100441dffe913f76abGreg Hackmann
46c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CR2_FREQ(x)     ((x) & I2C_CR2_FREQ_MASK)
470840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_FREQ_MASK   0x3F
480840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITERREN     (1 << 8)
490840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITEVTEN     (1 << 9)
500840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_ITBUFEN     (1 << 10)
510840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_DMAEN       (1 << 11)
520840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_CR2_LAST        (1 << 12)
530840b67ad4db1415094691100441dffe913f76abGreg Hackmann
54c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD7(x)    (((x) & I2C_OAR1_ADD7_MASK) << 1)
55c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD7_MASK  0x7F
56c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD10(x)   ((x) & I2C_OAR1_ADD10_MASK)
57c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_OAR1_ADD10_MASK 0x3FF
580840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_OAR1_ADDMODE    (1 << 15)
590840b67ad4db1415094691100441dffe913f76abGreg Hackmann
600840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_SB          (1 << 0)
610840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ADDR        (1 << 1)
620840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_BTF         (1 << 2)
630840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ADD10       (1 << 3)
640840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_STOPF       (1 << 4)
650840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_RXNE        (1 << 6)
660840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_TXE         (1 << 7)
670840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_BERR        (1 << 8)
680840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_ARLO        (1 << 9)
690840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_AF          (1 << 10)
700840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_OVR         (1 << 11)
710840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_PECERR      (1 << 12)
720840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_TIMEOUT     (1 << 14)
730840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR1_SMBALERT    (1 << 15)
740840b67ad4db1415094691100441dffe913f76abGreg Hackmann
750840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_MSL         (1 << 0)
760840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_BUSY        (1 << 1)
770840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_TRA         (1 << 2)
780840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_GENCALL     (1 << 4)
790840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_SMBDEFAULT  (1 << 5)
800840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_SMBHOST     (1 << 6)
810840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define I2C_SR2_DUALF       (1 << 7)
820840b67ad4db1415094691100441dffe913f76abGreg Hackmann
83c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR(x)          ((x) & I2C_CCR_MASK)
84c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_MASK        0xFFF
85c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_DUTY_16_9   (1 << 14)
86c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_CCR_FM          (1 << 15)
87c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
88c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_TRISE(x)        ((x) & I2C_TRISE_MASK)
89c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema#define I2C_TRISE_MASK      0x3F
90c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
91a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2c {
920840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CR1;
930840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CR2;
940840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t OAR1;
950840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t OAR2;
960840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t DR;
970840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t SR1;
980840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t SR2;
990840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t CCR;
1000840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t TRISE;
1010840b67ad4db1415094691100441dffe913f76abGreg Hackmann    volatile uint32_t FLTR;
1020840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1030840b67ad4db1415094691100441dffe913f76abGreg Hackmann
10481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemaenum StmI2cSpiMasterState
10581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
10681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_IDLE,
10781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_START,
10881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_TX_ADDR,
10981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_TX_DATA,
11081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_RX_ADDR,
11181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    STM_I2C_MASTER_RX_DATA,
11281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
11381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
114a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct I2cStmState {
1150840b67ad4db1415094691100441dffe913f76abGreg Hackmann    struct {
1160840b67ad4db1415094691100441dffe913f76abGreg Hackmann        union {
1170840b67ad4db1415094691100441dffe913f76abGreg Hackmann            uint8_t *buf;
1180840b67ad4db1415094691100441dffe913f76abGreg Hackmann            const uint8_t *cbuf;
1199ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            uint8_t byte;
1200840b67ad4db1415094691100441dffe913f76abGreg Hackmann        };
1210840b67ad4db1415094691100441dffe913f76abGreg Hackmann        size_t size;
1220840b67ad4db1415094691100441dffe913f76abGreg Hackmann        size_t offset;
1239ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        bool preamble;
1240840b67ad4db1415094691100441dffe913f76abGreg Hackmann
125a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        I2cCallbackF callback;
1260840b67ad4db1415094691100441dffe913f76abGreg Hackmann        void *cookie;
1270840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } rx, tx;
1280840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1290840b67ad4db1415094691100441dffe913f76abGreg Hackmann    enum {
130c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_DISABLED,
131c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_SLAVE,
132c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_MASTER,
133c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } mode;
134c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
135c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    enum {
136c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        STM_I2C_SLAVE_IDLE,
1370840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_RX_ARMED,
1380840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_RX,
1390840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_TX_ARMED,
1400840b67ad4db1415094691100441dffe913f76abGreg Hackmann        STM_I2C_SLAVE_TX,
141a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    } slaveState;
142c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
14381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    // StmI2cSpiMasterState
14481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState;
1450840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1460840b67ad4db1415094691100441dffe913f76abGreg Hackmann
147a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2cCfg {
148a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct StmI2c *regs;
1490840b67ad4db1415094691100441dffe913f76abGreg Hackmann
1500840b67ad4db1415094691100441dffe913f76abGreg Hackmann    uint32_t clock;
1510840b67ad4db1415094691100441dffe913f76abGreg Hackmann
152895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    IRQn_Type irqEv;
153895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    IRQn_Type irqEr;
1540840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1550840b67ad4db1415094691100441dffe913f76abGreg Hackmann
156a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstruct StmI2cDev {
157895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg;
158de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board;
159a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState state;
1600840b67ad4db1415094691100441dffe913f76abGreg Hackmann
16181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t next;
16281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t last;
16381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
164366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg    struct Gpio scl;
165366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg    struct Gpio sda;
166342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg
167342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg    uint8_t addr;
1680840b67ad4db1415094691100441dffe913f76abGreg Hackmann};
1690840b67ad4db1415094691100441dffe913f76abGreg Hackmann
17081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic const struct StmI2cCfg mStmI2cCfgs[] = {
17181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [0] = {
17281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C1_BASE,
17381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
17481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C1,
17581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
17681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C1_EV_IRQn,
17781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C1_ER_IRQn,
17881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
17981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [1] = {
18081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C2_BASE,
18181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
18281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C2,
18381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
18481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C2_EV_IRQn,
18581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C2_ER_IRQn,
18681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
18781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    [2] = {
18881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .regs = (struct StmI2c *)I2C3_BASE,
18981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .clock = PERIPH_APB1_I2C3,
19181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEv = I2C3_EV_IRQn,
19381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        .irqEr = I2C3_ER_IRQn,
19481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    },
19581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
19681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic struct StmI2cDev mStmI2cDevs[ARRAY_SIZE(mStmI2cCfgs)];
19881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
19981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastruct StmI2cXfer
20081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
20181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t        id;
20281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    const void     *txBuf;
20381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    size_t          txSize;
20481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    void           *rxBuf;
20581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    size_t          rxSize;
20681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    I2cCallbackF    callback;
20781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    void           *cookie;
208342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg    uint8_t         busId; /* for us these are both fine in a uint 8 */
209342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg    uint8_t         addr;
21081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema};
21181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21281be7381e3399a0ff4c54222987ab7bd0b1169dfBen FennemaATOMIC_BITSET_DECL(mXfersValid, I2C_MAX_QUEUE_DEPTH, static);
21381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic struct StmI2cXfer mXfers[I2C_MAX_QUEUE_DEPTH] = { };
21481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic inline struct StmI2cXfer *stmI2cGetXfer(void)
21681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
21781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    int32_t idx = atomicBitsetFindClearAndSet(mXfersValid);
21881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
21981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (idx < 0)
22081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return NULL;
22181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    else
22281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return mXfers + idx;
22381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema}
22481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
22581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennemastatic inline void stmI2cPutXfer(struct StmI2cXfer *xfer)
22681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema{
22781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (xfer)
22881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicBitsetClearBit(mXfersValid, xfer - mXfers);
22981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema}
23081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
231b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cAckEnable(struct StmI2cDev *pdev)
2320840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
233895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 |= I2C_CR1_ACK;
2340840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2350840b67ad4db1415094691100441dffe913f76abGreg Hackmann
236b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cAckDisable(struct StmI2cDev *pdev)
2370840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
238895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 &= ~I2C_CR1_ACK;
2390840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2400840b67ad4db1415094691100441dffe913f76abGreg Hackmann
2411a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cDmaEnable(struct StmI2cDev *pdev)
2421a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
2431a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    pdev->cfg->regs->CR2 |= I2C_CR2_DMAEN;
2441a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
2451a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
2461a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cDmaDisable(struct StmI2cDev *pdev)
2471a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
2481a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    pdev->cfg->regs->CR2 &= ~I2C_CR2_DMAEN;
2491a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
2501a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
251b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cStopEnable(struct StmI2cDev *pdev)
252c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
2536b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
2546b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2556b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    while (regs->CR1 & (I2C_CR1_STOP | I2C_CR1_START))
2566b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann        ;
2576b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    regs->CR1 |= I2C_CR1_STOP;
2586b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann}
2596b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2606b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmannstatic inline void stmI2cStartEnable(struct StmI2cDev *pdev)
2616b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann{
2626b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
2636b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann
2646b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    while (regs->CR1 & (I2C_CR1_STOP | I2C_CR1_START))
2656b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann        ;
2666b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann    regs->CR1 |= I2C_CR1_START;
267c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
268c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
269b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cIrqEnable(struct StmI2cDev *pdev,
2700840b67ad4db1415094691100441dffe913f76abGreg Hackmann        uint32_t mask)
2710840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
272895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR2 |= mask;
2730840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2740840b67ad4db1415094691100441dffe913f76abGreg Hackmann
275b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cIrqDisable(struct StmI2cDev *pdev,
2760840b67ad4db1415094691100441dffe913f76abGreg Hackmann        uint32_t mask)
2770840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
278895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR2 &= ~mask;
2790840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2800840b67ad4db1415094691100441dffe913f76abGreg Hackmann
281a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cEnable(struct StmI2cDev *pdev)
2820840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
283895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 |= I2C_CR1_PE;
2840840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2850840b67ad4db1415094691100441dffe913f76abGreg Hackmann
286a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cDisable(struct StmI2cDev *pdev)
2870840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
288895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    pdev->cfg->regs->CR1 &= ~I2C_CR1_PE;
2890840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
2900840b67ad4db1415094691100441dffe913f76abGreg Hackmann
291a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cSpeedSet(struct StmI2cDev *pdev,
292342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinberg        const uint32_t speed)
293c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
294895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
295c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    int ccr, ccr_1, ccr_2;
296c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    int apb1_clk;
297c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
298c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    apb1_clk = pwrGetBusSpeed(PERIPH_BUS_APB1);
299c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
300c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    regs->CR2 = (regs->CR2 & ~I2C_CR2_FREQ_MASK) |
301c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema                 I2C_CR2_FREQ(apb1_clk / 1000000);
302c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
303c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (speed <= 100000) {
304c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr = apb1_clk / (speed * 2);
305c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr < 4)
306c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr = 4;
307c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->CCR = I2C_CCR(ccr);
308c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
309c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->TRISE = I2C_TRISE((apb1_clk / 1000000) + 1);
310c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (speed <= 400000) {
311c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr_1 = apb1_clk / (speed * 3);
312c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr_1 == 0 || apb1_clk / (ccr_1 * 3) > speed)
313c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr_1 ++;
314c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        ccr_2 = apb1_clk / (speed * 25);
315c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (ccr_2 == 0 || apb1_clk / (ccr_2 * 25) > speed)
316c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            ccr_2 ++;
317c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
318c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if ((apb1_clk / (ccr_1 * 3)) > (apb1_clk / (ccr_2 * 25)))
319c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->CCR = I2C_CCR_FM | I2C_CCR(ccr_1);
320c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        else
321c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->CCR = I2C_CCR_FM | I2C_CCR_DUTY_16_9 | I2C_CCR(ccr_2);
322c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
323c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->TRISE = I2C_TRISE(((3*apb1_clk)/10000000) + 1);
324c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
325c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
326c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
327a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic inline void stmI2cSlaveIdle(struct StmI2cDev *pdev)
3280840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
329a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
3300840b67ad4db1415094691100441dffe913f76abGreg Hackmann
331a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    state->slaveState = STM_I2C_SLAVE_RX_ARMED;
332b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cAckEnable(pdev);
333b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
3340840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3350840b67ad4db1415094691100441dffe913f76abGreg Hackmann
336b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveRxDone(struct StmI2cDev *pdev)
3370840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
338a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
339a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    size_t rxOffst = state->rx.offset;
3400840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3410840b67ad4db1415094691100441dffe913f76abGreg Hackmann    state->rx.offset = 0;
34262a051ff2d95252651580d9653b391bf94e756fbGreg Hackmann    state->rx.callback(state->rx.cookie, 0, rxOffst, 0);
3430840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3440840b67ad4db1415094691100441dffe913f76abGreg Hackmann
345b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveTxDone(struct StmI2cDev *pdev)
3460840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
347a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
348a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    size_t txOffst = state->tx.offset;
3490840b67ad4db1415094691100441dffe913f76abGreg Hackmann
350a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cSlaveIdle(pdev);
35162a051ff2d95252651580d9653b391bf94e756fbGreg Hackmann    state->tx.callback(state->tx.cookie, txOffst, 0, 0);
352c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
353c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
354b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveTxNextByte(struct StmI2cDev *pdev)
3550840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
356a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
357895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3580840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3599ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    if (state->tx.preamble) {
3609ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        regs->DR = state->tx.byte;
3619ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->tx.offset++;
3629ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    } else if (state->tx.offset < state->tx.size) {
3630840b67ad4db1415094691100441dffe913f76abGreg Hackmann        regs->DR = state->tx.cbuf[state->tx.offset];
3640840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->tx.offset++;
3650840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
3669ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->slaveState = STM_I2C_SLAVE_TX_ARMED;
367b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN);
3689ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        state->tx.callback(state->tx.cookie, state->tx.offset, 0, 0);
3690840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
3700840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3710840b67ad4db1415094691100441dffe913f76abGreg Hackmann
372b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveAddrMatched(struct StmI2cDev *pdev)
3730840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
374a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
375895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3760840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3770840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("addr");
3780840b67ad4db1415094691100441dffe913f76abGreg Hackmann
379a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_RX_ARMED) {
380a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_RX;
381b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
382d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann    } else if (state->slaveState == STM_I2C_SLAVE_TX) {
383b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN | I2C_CR2_ITERREN);
3840840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
385c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    /* clear ADDR by doing a dummy reads from SR1 (already read) then SR2 */
3860840b67ad4db1415094691100441dffe913f76abGreg Hackmann    (void)regs->SR2;
3870840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
3880840b67ad4db1415094691100441dffe913f76abGreg Hackmann
389b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveStopRxed(struct StmI2cDev *pdev)
3900840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
391895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
3920840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3930840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("stopf");
3940840b67ad4db1415094691100441dffe913f76abGreg Hackmann
3950840b67ad4db1415094691100441dffe913f76abGreg Hackmann    (void)regs->SR1;
396a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cEnable(pdev);
3970840b67ad4db1415094691100441dffe913f76abGreg Hackmann    /* clear STOPF by doing a dummy read from SR1 and strobing the PE bit */
3980840b67ad4db1415094691100441dffe913f76abGreg Hackmann
399a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    stmI2cSlaveIdle(pdev);
400b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    stmI2cSlaveRxDone(pdev);
4010840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4020840b67ad4db1415094691100441dffe913f76abGreg Hackmann
403b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic inline void stmI2cSlaveRxBufNotEmpty(struct StmI2cDev *pdev)
4040840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
405a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
406895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4070840b67ad4db1415094691100441dffe913f76abGreg Hackmann    uint8_t data = regs->DR;
4080840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4090840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("rxne");
4100840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4110840b67ad4db1415094691100441dffe913f76abGreg Hackmann    if (state->rx.offset < state->rx.size) {
4120840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->rx.buf[state->rx.offset] = data;
4130840b67ad4db1415094691100441dffe913f76abGreg Hackmann        state->rx.offset++;
4140840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
415b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
4160840b67ad4db1415094691100441dffe913f76abGreg Hackmann        /* TODO: error on overflow */
4170840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4180840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4190840b67ad4db1415094691100441dffe913f76abGreg Hackmann
420b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveTxBufEmpty(struct StmI2cDev *pdev)
4210840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
422a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
4230840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4240840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("txe");
4250840b67ad4db1415094691100441dffe913f76abGreg Hackmann
426a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_RX) {
427a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_TX_ARMED;
428b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITBUFEN);
429b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
430b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveRxDone(pdev);
431b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        /* stmI2cTxNextByte() will happen when the task provides a
4320840b67ad4db1415094691100441dffe913f76abGreg Hackmann           TX buffer; the I2C controller will stretch the clock until then */
4330840b67ad4db1415094691100441dffe913f76abGreg Hackmann    } else {
434b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveTxNextByte(pdev);
4350840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4360840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4370840b67ad4db1415094691100441dffe913f76abGreg Hackmann
438b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cSlaveNakRxed(struct StmI2cDev *pdev)
4390840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
440a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
441895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
4420840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4430840b67ad4db1415094691100441dffe913f76abGreg Hackmann    i2c_log_debug("af");
4440840b67ad4db1415094691100441dffe913f76abGreg Hackmann
445a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    if (state->slaveState == STM_I2C_SLAVE_TX) {
446d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        state->tx.offset--;
447d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        /* NACKs seem to be preceded by a spurious TXNE, so adjust the offset to
448d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann           compensate (the corresponding byte written to DR was never actually
449d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann           transmitted) */
450b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cSlaveTxDone(pdev);
4510840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
4520840b67ad4db1415094691100441dffe913f76abGreg Hackmann    regs->SR1 &= ~I2C_SR1_AF;
4530840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
4540840b67ad4db1415094691100441dffe913f76abGreg Hackmann
4551a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cMasterTxRxDone(struct StmI2cDev *pdev, int err)
456b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann{
457b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    struct I2cStmState *state = &pdev->state;
458b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    size_t txOffst = state->tx.offset;
459b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    size_t rxOffst = state->rx.offset;
460b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    uint32_t id;
461b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    int i;
462b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    struct StmI2cXfer *xfer;
463b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
464287671677bb946b266dc4c8fc39582533272363cBen Fennema    if (pdev->board->sleepDev >= 0)
465287671677bb946b266dc4c8fc39582533272363cBen Fennema        platReleaseDevInSleepMode(pdev->board->sleepDev);
466ec0212a59091de0329e30b8a916f63fca519b946Ben Fennema
467b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    state->tx.offset = 0;
468b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    state->rx.offset = 0;
4691a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.callback(state->tx.cookie, txOffst, rxOffst, err);
470b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
471b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    do {
472b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        id = atomicAdd(&pdev->next, 1);
473b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    } while (!id);
474b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
475b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    for (i=0; i<I2C_MAX_QUEUE_DEPTH; i++) {
476b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        xfer = &mXfers[i];
477b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
478b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        if (xfer->busId == (pdev - mStmI2cDevs) &&
479b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                atomicCmpXchg32bits(&xfer->id, id, 0)) {
480b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            pdev->addr = xfer->addr;
481b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.cbuf = xfer->txBuf;
482b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.offset = 0;
483b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.size = xfer->txSize;
484b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.callback = xfer->callback;
485b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->tx.cookie = xfer->cookie;
486b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.buf = xfer->rxBuf;
487b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.offset = 0;
488b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.size = xfer->rxSize;
489b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.callback = NULL;
490b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            state->rx.cookie = NULL;
491b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            atomicWriteByte(&state->masterState, STM_I2C_MASTER_START);
492287671677bb946b266dc4c8fc39582533272363cBen Fennema            if (pdev->board->sleepDev >= 0)
493287671677bb946b266dc4c8fc39582533272363cBen Fennema                platRequestDevInSleepMode(pdev->board->sleepDev, 12);
494b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cPutXfer(xfer);
4956b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann            stmI2cStartEnable(pdev);
496b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            return;
497b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        }
498b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    }
499b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
500b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann    atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE);
501b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann}
502b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann
5031a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic void stmI2cMasterDmaTxDone(void *cookie, uint16_t bytesLeft, int err)
5041a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5051a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2cDev *pdev = cookie;
5061a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct I2cStmState *state = &pdev->state;
5071a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
5081a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5091a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.offset = state->tx.size - bytesLeft;
5101a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->tx.size = 0;
5111a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaDisable(pdev);
5121a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    if (err == 0 && state->rx.size > 0) {
5131a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        atomicWriteByte(&state->masterState, STM_I2C_MASTER_START);
5141a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cStartEnable(pdev);
5151a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    } else {
5161a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        while (!(regs->SR1 & I2C_SR1_BTF))
5171a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            ;
5181a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5191a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cStopEnable(pdev);
5201a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterTxRxDone(pdev, err);
5211a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    }
5221a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5231a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5241a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic void stmI2cMasterDmaRxDone(void *cookie, uint16_t bytesLeft, int err)
5251a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5261a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2cDev *pdev = cookie;
5271a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct I2cStmState *state = &pdev->state;
5281a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5291a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->rx.offset = state->rx.size - bytesLeft;
5301a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    state->rx.size = 0;
5311a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5321a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaDisable(pdev);
5331a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cStopEnable(pdev);
5341a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cMasterTxRxDone(pdev, err);
5351a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5361a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
537102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic inline void stmI2cMasterDmaCancel(struct StmI2cDev *pdev)
538102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
539102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct I2cStmState *state = &pdev->state;
540102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
541102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    dmaStop(I2C_DMA_BUS, pdev->board->dmaRx.stream);
542102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    state->rx.offset = state->rx.size - dmaBytesLeft(I2C_DMA_BUS,
543102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            pdev->board->dmaRx.stream);
544102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    dmaStop(I2C_DMA_BUS, pdev->board->dmaTx.stream);
545102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    state->tx.offset = state->tx.size - dmaBytesLeft(I2C_DMA_BUS,
546102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            pdev->board->dmaTx.stream);
547102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
548102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cDmaDisable(pdev);
549102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
550102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
5511a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmannstatic inline void stmI2cMasterStartDma(struct StmI2cDev *pdev,
5521a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        const struct StmI2cDmaCfg *dmaCfg, const void *buf,
5531a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        size_t size, DmaCallbackF callback, bool rx, bool last)
5541a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann{
5551a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
5561a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    struct dmaMode mode;
5571a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5581a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    memset(&mode, 0, sizeof(mode));
5591a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.priority = DMA_PRIORITY_HIGH;
5601a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.direction = rx ? DMA_DIRECTION_PERIPH_TO_MEM :
5611a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            DMA_DIRECTION_MEM_TO_PERIPH;
5621a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.periphAddr = (uintptr_t)&regs->DR;
5631a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.minc = true;
5641a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    mode.channel = dmaCfg->channel;
5651a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
5661a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    dmaStart(I2C_DMA_BUS, dmaCfg->stream, buf, size, &mode, callback, pdev);
5671a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    if (last)
5681a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_LAST);
5691a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    else
5701a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_LAST);
5711a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann    stmI2cDmaEnable(pdev);
5721a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann}
5731a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
574b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterSentStart(struct StmI2cDev *pdev)
5750840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
576a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
577895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
5780840b67ad4db1415094691100441dffe913f76abGreg Hackmann
57981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (atomicReadByte(&state->masterState) == STM_I2C_MASTER_START) {
580c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (state->tx.size > 0) {
58181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            atomicWriteByte(&state->masterState, STM_I2C_MASTER_TX_ADDR);
582c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->DR = pdev->addr << 1;
583c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else {
58481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            atomicWriteByte(&state->masterState, STM_I2C_MASTER_RX_ADDR);
585b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cAckEnable(pdev);
586c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            regs->DR = (pdev->addr << 1) | 0x01;
587c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        }
588c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
5890840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
5900840b67ad4db1415094691100441dffe913f76abGreg Hackmann
591b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterSentAddr(struct StmI2cDev *pdev)
5920840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
593a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
594895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
59581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState = atomicReadByte(&state->masterState);
5960840b67ad4db1415094691100441dffe913f76abGreg Hackmann
59781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (masterState == STM_I2C_MASTER_TX_ADDR) {
5981a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterStartDma(pdev, &pdev->board->dmaTx, state->tx.cbuf,
5991a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->tx.size, stmI2cMasterDmaTxDone, false, !!state->rx.size);
600c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR2; // Clear ADDR
60181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_TX_DATA);
60281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    } else if (masterState == STM_I2C_MASTER_RX_ADDR) {
603c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (state->rx.size == 1) // Generate NACK here for 1 byte transfers
604b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cAckDisable(pdev);
6051a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
6061a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterStartDma(pdev, &pdev->board->dmaRx, state->rx.buf,
6071a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->rx.size, stmI2cMasterDmaRxDone, true,
6081a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann                state->rx.size > 1);
609c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR2; // Clear ADDR
61081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_RX_DATA);
611c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
612c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
613c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
614b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmannstatic void stmI2cMasterNakRxed(struct StmI2cDev *pdev)
615c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
616a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
617895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
61881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint8_t masterState = atomicReadByte(&state->masterState);
619c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
62081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (masterState == STM_I2C_MASTER_TX_ADDR ||
62181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_TX_DATA ||
62281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_RX_ADDR ||
62381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            masterState == STM_I2C_MASTER_RX_DATA) {
624102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        stmI2cMasterDmaCancel(pdev);
6251a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann
626c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        regs->SR1 &= ~I2C_SR1_AF;
627b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cStopEnable(pdev);
6281a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cMasterTxRxDone(pdev, 0);
629c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
630c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
631c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
632102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic void stmI2cMasterBusError(struct StmI2cDev *pdev)
633102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
634102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
635102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
636102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterDmaCancel(pdev);
637102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    regs->SR1 &= ~I2C_SR1_BERR;
638102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterTxRxDone(pdev, EIO);
639102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
640102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
641102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic void stmI2cMasterArbitrationLoss(struct StmI2cDev *pdev)
642102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
643102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
644102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
645102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterDmaCancel(pdev);
646102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    regs->SR1 &= ~I2C_SR1_ARLO;
647102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterTxRxDone(pdev, EBUSY);
648102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
649102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
650102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmannstatic void stmI2cMasterUnexpectedError(struct StmI2cDev *pdev)
651102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann{
652102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    struct StmI2c *regs = pdev->cfg->regs;
653102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
654102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    osLog(LOG_ERROR, "Unexpected I2C ERR interrupt: SR1 = %04lX, SR2 = %04lX\n",
655102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            regs->SR1, regs->SR2);
656102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
657102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterDmaCancel(pdev);
658102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    regs->SR1 = 0;
659102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann    stmI2cMasterTxRxDone(pdev, EIO);
660102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann}
661102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann
662a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic void stmI2cIsrEvent(struct StmI2cDev *pdev)
663c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
664895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
665c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    uint16_t sr1 = regs->SR1;
666c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
667c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
668c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_ADDR) {
669b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveAddrMatched(pdev);
670c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_RXNE) {
671b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveRxBufNotEmpty(pdev);
672c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_TXE) {
673b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveTxBufEmpty(pdev);
674c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        } else if (sr1 & I2C_SR1_BTF) {
675c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            if (regs->SR2 & I2C_SR2_TRA)
676b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                stmI2cSlaveTxBufEmpty(pdev);
677c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema           else
678b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann                stmI2cSlaveRxBufNotEmpty(pdev);
679d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        } else if (sr1 & I2C_SR1_STOPF) {
680b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveStopRxed(pdev);
681c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        }
682c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        /* TODO: other flags */
683c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (pdev->state.mode == STM_I2C_MASTER) {
684c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_SB)
685b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterSentStart(pdev);
686c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        else if (sr1 & I2C_SR1_ADDR)
687b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterSentAddr(pdev);
688c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
689c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
690c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
691a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinbergstatic void stmI2cIsrError(struct StmI2cDev *pdev)
692c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
693895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2c *regs = pdev->cfg->regs;
694c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    uint16_t sr1 = regs->SR1;
695c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
696c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
697c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_AF)
698b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveNakRxed(pdev);
699c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        /* TODO: other flags */
700c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else if (pdev->state.mode == STM_I2C_MASTER) {
701c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        if (sr1 & I2C_SR1_AF)
702b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cMasterNakRxed(pdev);
703102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        else if (sr1 & I2C_SR1_BERR)
704102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            stmI2cMasterBusError(pdev);
705102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        else if (sr1 & I2C_SR1_ARLO)
706102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            stmI2cMasterArbitrationLoss(pdev);
707102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann        else
708102610d413fb2a73ed2dd0b8a059117190fd2de0Greg Hackmann            stmI2cMasterUnexpectedError(pdev);
709c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
7100840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
7110840b67ad4db1415094691100441dffe913f76abGreg Hackmann
7120840b67ad4db1415094691100441dffe913f76abGreg Hackmann#define DECLARE_IRQ_HANDLERS(_n)                \
7130840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_EV_IRQHandler();      \
7140840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_ER_IRQHandler();      \
7150840b67ad4db1415094691100441dffe913f76abGreg Hackmann                                                \
7160840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_EV_IRQHandler()       \
7170840b67ad4db1415094691100441dffe913f76abGreg Hackmann    {                                           \
718895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cIsrEvent(&mStmI2cDevs[_n - 1]);  \
7190840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }                                           \
7200840b67ad4db1415094691100441dffe913f76abGreg Hackmann                                                \
7210840b67ad4db1415094691100441dffe913f76abGreg Hackmann    extern void I2C##_n##_ER_IRQHandler()       \
7220840b67ad4db1415094691100441dffe913f76abGreg Hackmann    {                                           \
723895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cIsrError(&mStmI2cDevs[_n - 1]);  \
7240840b67ad4db1415094691100441dffe913f76abGreg Hackmann    }
7250840b67ad4db1415094691100441dffe913f76abGreg Hackmann
726895ed4022a50ee173631b04b791fe13114bcdd55Ben FennemaDECLARE_IRQ_HANDLERS(1);
727e0771b85c97ed0a90ff0824530a98f4f69e9b1a9Ben FennemaDECLARE_IRQ_HANDLERS(3);
728895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
729de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmannstatic inline void stmI2cGpioInit(struct Gpio *gpio,
730de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        const struct StmI2cBoardCfg *board, const struct StmI2cGpioCfg *cfg)
7310840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
732de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    gpioRequest(gpio, cfg->num);
733de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    gpioConfigAlt(gpio, board->gpioSpeed, board->gpioPull, GPIO_OUT_OPEN_DRAIN,
734de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann            cfg->func);
7350840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
7360840b67ad4db1415094691100441dffe913f76abGreg Hackmann
737342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cMasterRequest(uint32_t busId, uint32_t speed)
7380840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
739895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
7400840b67ad4db1415094691100441dffe913f76abGreg Hackmann        return -EINVAL;
7410840b67ad4db1415094691100441dffe913f76abGreg Hackmann
742de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
743de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    if (!board)
744de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        return -EINVAL;
745de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann
746895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
74781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct I2cStmState *state = &pdev->state;
748895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = &mStmI2cCfgs[busId];
7490840b67ad4db1415094691100441dffe913f76abGreg Hackmann
75081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode == STM_I2C_DISABLED) {
75181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        state->mode = STM_I2C_MASTER;
752895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
753895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pdev->cfg = cfg;
754de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        pdev->board = board;
75581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        pdev->next = 2;
75681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        pdev->last = 1;
75781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicBitsetInit(mXfersValid, I2C_MAX_QUEUE_DEPTH);
758895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema
759de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->scl, board, &board->gpioScl);
760de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->sda, board, &board->gpioSda);
761c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
762c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, true);
763c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
764a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cDisable(pdev);
765c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
766c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, true);
767c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, false);
7680840b67ad4db1415094691100441dffe913f76abGreg Hackmann
7691a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITEVTEN | I2C_CR2_ITERREN);
770a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cSpeedSet(pdev, speed);
77181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE);
772c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
773895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEr);
774895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEv);
775c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
776a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cEnable(pdev);
777c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
778c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
779c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
780c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
7810840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
7820840b67ad4db1415094691100441dffe913f76abGreg Hackmann
783342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cMasterRelease(uint32_t busId)
7840840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
785895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
786c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
787c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
788895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
78981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct I2cStmState *state = &pdev->state;
790895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
7910840b67ad4db1415094691100441dffe913f76abGreg Hackmann
79281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode == STM_I2C_MASTER) {
793ddcba9d9835dc96c06488f56f55e5835a46eaff3Ben Fennema        if (atomicReadByte(&state->masterState) == STM_I2C_MASTER_IDLE) {
794ddcba9d9835dc96c06488f56f55e5835a46eaff3Ben Fennema            state->mode = STM_I2C_DISABLED;
7951a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann            stmI2cIrqEnable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
79681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            stmI2cDisable(pdev);
79781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, false);
79881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            return 0;
79981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        } else {
80081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            return -EBUSY;
80181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        }
802c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
80381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return -EINVAL;
804c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
805c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
8060840b67ad4db1415094691100441dffe913f76abGreg Hackmann
80781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
808342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cMasterTxRx(uint32_t busId, uint32_t addr,
809895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        const void *txBuf, size_t txSize, void *rxBuf, size_t rxSize,
810895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        I2cCallbackF callback, void *cookie)
811c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
81281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    uint32_t id;
81381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
814895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
815c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
816c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    else if (addr & 0x80)
817c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -ENXIO;
8180840b67ad4db1415094691100441dffe913f76abGreg Hackmann
819895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
820a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
8210840b67ad4db1415094691100441dffe913f76abGreg Hackmann
82281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (state->mode != STM_I2C_MASTER)
82381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        return -EINVAL;
824c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
82581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    struct StmI2cXfer *xfer = stmI2cGetXfer();
82681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
82781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema    if (xfer) {
82881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->busId = busId;
82981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->addr = addr;
83081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->txBuf = txBuf;
83181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->txSize = txSize;
83281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->rxBuf = rxBuf;
83381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->rxSize = rxSize;
83481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->callback = callback;
83581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        xfer->cookie = cookie;
83681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
83781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        do {
83881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            id = atomicAdd(&pdev->last, 1);
83981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        } while (!id);
84081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
84181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // after this point the transfer can be picked up by the transfer
84281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // complete interrupt
84381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        atomicWrite32bits(&xfer->id, id);
84481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema
84581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // only initiate transfer here if we are in IDLE. Otherwise the transfer
84681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // completion interrupt will start the next transfer (not necessarily
84781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        // this one)
84881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        if (atomicCmpXchgByte((uint8_t *)&state->masterState,
84981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                STM_I2C_MASTER_IDLE, STM_I2C_MASTER_START)) {
85081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            // it is possible for this transfer to already be complete by the
85181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            // time we get here. if so, transfer->id will have been set to 0.
85281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            if (atomicCmpXchg32bits(&xfer->id, id, 0)) {
85381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                pdev->addr = xfer->addr;
85481be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.cbuf = xfer->txBuf;
85581be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.offset = 0;
85681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.size = xfer->txSize;
85781be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.callback = xfer->callback;
85881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->tx.cookie = xfer->cookie;
85981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.buf = xfer->rxBuf;
86081be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.offset = 0;
86181be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.size = xfer->rxSize;
86281be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.callback = NULL;
86381be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                state->rx.cookie = NULL;
864287671677bb946b266dc4c8fc39582533272363cBen Fennema                if (pdev->board->sleepDev >= 0)
865287671677bb946b266dc4c8fc39582533272363cBen Fennema                    platRequestDevInSleepMode(pdev->board->sleepDev, 12);
86681be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema                stmI2cPutXfer(xfer);
8676b8a5ad6a9b658df8ed5ea52fcc5df53d6c41fd6Greg Hackmann                stmI2cStartEnable(pdev);
86881be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema            }
86981be7381e3399a0ff4c54222987ab7bd0b1169dfBen Fennema        }
870c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
871c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
872c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
873c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
8740840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
8750840b67ad4db1415094691100441dffe913f76abGreg Hackmann
876342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveRequest(uint32_t busId, uint32_t addr)
8770840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
878895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
879c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
880c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
881de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
882de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann    if (!board)
883de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        return -EINVAL;
884de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann
885895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
886895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = &mStmI2cCfgs[busId];
887c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
888c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_DISABLED) {
889c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->state.mode = STM_I2C_SLAVE;
890c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
891c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->addr = addr;
892895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pdev->cfg = cfg;
893de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        pdev->board = board;
8940840b67ad4db1415094691100441dffe913f76abGreg Hackmann
895de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->scl, board, &board->gpioScl);
896de3e8ff2e1ff562311016c30c4c93d9acf95442fGreg Hackmann        stmI2cGpioInit(&pdev->sda, board, &board->gpioSda);
897c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
898c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
899c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
9000840b67ad4db1415094691100441dffe913f76abGreg Hackmann        return -EBUSY;
901c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
902c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
9030840b67ad4db1415094691100441dffe913f76abGreg Hackmann
904342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveRelease(uint32_t busId)
905c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
906895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    if (busId >= ARRAY_SIZE(mStmI2cDevs))
907c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EINVAL;
9080840b67ad4db1415094691100441dffe913f76abGreg Hackmann
909895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
910895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
911a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
912c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
913c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pdev->state.mode = STM_I2C_DISABLED;
9141a56d7dbff3c06f7b55084aa5ec9f75e1f061ac1Greg Hackmann        stmI2cIrqDisable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
915b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckDisable(pdev);
916895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        stmI2cDisable(pdev);
917895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, false);
918c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
919c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
920c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
921c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
9220840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
923a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
924342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergvoid i2cSlaveEnableRx(uint32_t busId, void *rxBuf, size_t rxSize,
925a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        I2cCallbackF callback, void *cookie)
9260840b67ad4db1415094691100441dffe913f76abGreg Hackmann{
927895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
928895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    const struct StmI2cCfg *cfg = pdev->cfg;
929a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
930a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
931c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
932366407f628e806b2b48ccc36e5a2ac5df914f9cbDmitry Grinberg        state->rx.buf = rxBuf;
933c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.offset = 0;
934895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        state->rx.size = rxSize;
935c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.callback = callback;
936c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->rx.cookie = cookie;
937a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        state->slaveState = STM_I2C_SLAVE_RX_ARMED;
938c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
939c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitClock(PERIPH_BUS_APB1, cfg->clock, true);
940c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, true);
941c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        pwrUnitReset(PERIPH_BUS_APB1, cfg->clock, false);
942c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
943895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEr);
944895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        NVIC_EnableIRQ(cfg->irqEv);
945c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
946a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg        stmI2cEnable(pdev);
947c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        cfg->regs->OAR1 = I2C_OAR1_ADD7(pdev->addr);
948b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cIrqEnable(pdev, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN);
949b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann        stmI2cAckEnable(pdev);
950c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
9510840b67ad4db1415094691100441dffe913f76abGreg Hackmann}
952a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
953342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergstatic int i2cSlaveTx(uint32_t busId, const void *txBuf, uint8_t byte,
9549ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        size_t txSize, I2cCallbackF callback, void *cookie)
955c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema{
956895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema    struct StmI2cDev *pdev = &mStmI2cDevs[busId];
957a1acd43d08d2fe165f43ad3630974fe5a9d00977Dmitry Grinberg    struct I2cStmState *state = &pdev->state;
958c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
959c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    if (pdev->state.mode == STM_I2C_SLAVE) {
960d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        if (state->slaveState == STM_I2C_SLAVE_RX)
961c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema            return -EBUSY;
962a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
9639ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        if (txBuf) {
9649ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.cbuf = txBuf;
9659ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.preamble = false;
9669ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        } else {
9679ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.byte = byte;
9689ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->tx.preamble = true;
9699ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        }
970c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.offset = 0;
971895ed4022a50ee173631b04b791fe13114bcdd55Ben Fennema        state->tx.size = txSize;
972c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.callback = callback;
973c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        state->tx.cookie = cookie;
974a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
9759ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        if (state->slaveState == STM_I2C_SLAVE_TX_ARMED) {
9769ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann            state->slaveState = STM_I2C_SLAVE_TX;
977b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cSlaveTxNextByte(pdev);
978b1a01e920afed810350a633ee48112b75b9a3041Greg Hackmann            stmI2cIrqEnable(pdev, I2C_CR2_ITBUFEN);
979d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann        } else {
980d9b4be2f9f66404fa14bd43ad76ab852eb7690d5Greg Hackmann            state->slaveState = STM_I2C_SLAVE_TX;
9819ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        }
982c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema
983c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return 0;
984c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    } else {
985c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema        return -EBUSY;
986c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema    }
987c39f6795e17ef975d6a1e8912f4ff878b3dc4ba5Ben Fennema}
9889ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann
989342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveTxPreamble(uint32_t busId, uint8_t byte, I2cCallbackF callback,
9909ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        void *cookie)
9919ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann{
9929ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    return i2cSlaveTx(busId, NULL, byte, 0, callback, cookie);
9939ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann}
9949ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann
995342c37806ad0ac7d1e5d3f5dff74065d28e5ec3fDmitry Grinbergint i2cSlaveTxPacket(uint32_t busId, const void *txBuf, size_t txSize,
9969ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann        I2cCallbackF callback, void *cookie)
9979ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann{
9989ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann    return i2cSlaveTx(busId, txBuf, 0, txSize, callback, cookie);
9999ec8fea4cc8e5357e2e08d761b82d4379e9626caGreg Hackmann}
1000