<commit_before>/*
 * Copyright (C) 2015 <NAME> <<EMAIL>>
 *               2017 we-sens.com
 *               2018 Inria
 *               2018 HAW Hamburg
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @ingroup     cpu_stm32_common
 * @ingroup     drivers_periph_i2c
 * @{
 *
 * @file
 * @brief       Low-level I2C driver implementation
 *
 * This driver supports the STM32 F0, F3, F7, L0 and L4 families.
 * @note This implementation only implements the 7-bit addressing polling mode
 * (for now interrupt mode is not available)
 *
 * @author      <NAME> <peter.kietzmann@haw-hamburg.de>
 * @author      <NAME> <hauke.petersen@fu-berlin.de>
 * @auhtor      <NAME> <thomas.eichinger@fu-berlin.de>
 * @author      <NAME> <jan-pohlmann@gmx.de>
 * @author      <NAME> <<EMAIL>>
 * @author      <NAME> <alexandre.abadie@inria.fr>
 * @author      <NAME> <kevin.weiss@haw-hamburg.de>
 *
 * @}
 */

#include <stdint.h>
#include <errno.h>

#include "cpu.h"
#include "mutex.h"

#include "cpu_conf_stm32_common.h"

#include "periph/i2c.h"
#include "periph/gpio.h"
#include "periph_conf.h"

#define ENABLE_DEBUG    (0)
#include "debug.h"

#define TICK_TIMEOUT    (0xFFFF)
#define MAX_BYTES_PER_FRAME (256)

#define I2C_IRQ_PRIO    (1)
#define I2C_FLAG_READ   (I2C_READ << I2C_CR2_RD_WRN_Pos)
#define I2C_FLAG_WRITE  (0)

#define CLEAR_FLAG      (I2C_ICR_NACKCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ICR_ADDRCF)

/* static function definitions */
static inline void _i2c_init(I2C_TypeDef *i2c, uint32_t timing);
static int _write(I2C_TypeDef *i2c, uint16_t addr, const void *data,
                  size_t length, uint8_t flags, uint32_t cr2_flags);
static int _start(I2C_TypeDef *i2c, uint32_t cr2, uint8_t flags);
static int _stop(I2C_TypeDef *i2c);
static int _wait_isr_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags);
static inline int _wait_for_bus(I2C_TypeDef *i2c);

/**
 * @brief Array holding one pre-initialized mutex for each I2C device
 */
static mutex_t locks[I2C_NUMOF];

void i2c_init(i2c_t dev)
{
    assert(dev < I2C_NUMOF);

    DEBUG("[i2c] init: initializing device\n");
    mutex_init(&locks[dev]);

    I2C_TypeDef *i2c = i2c_config[dev].dev;

    periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);

    NVIC_SetPriority(i2c_config[dev].irqn, I2C_IRQ_PRIO);
    NVIC_EnableIRQ(i2c_config[dev].irqn);

#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
    /* Set I2CSW bits to enable I2C clock source */
    RCC->CFGR3 |= i2c_config[dev].rcc_sw_mask;
#endif

    DEBUG("[i2c] init: configuring pins\n");
    /* configure pins */
    gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU);
    gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af);
    gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU);
    gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af);

    DEBUG("[i2c] init: configuring device\n");
    /* set the timing register value from predefined values */
    i2c_timing_param_t tp = timing_params[i2c_config[dev].speed];
    uint32_t timing = (( (uint32_t)tp.presc << I2C_TIMINGR_PRESC_Pos) |
                       ( (uint32_t)tp.scldel << I2C_TIMINGR_SCLDEL_Pos) |
                       ( (uint32_t)tp.sdadel << I2C_TIMINGR_SDADEL_Pos) |
                       ( (uint16_t)tp.sclh << I2C_TIMINGR_SCLH_Pos) |
                       tp.scll);
    _i2c_init(i2c, timing);
}

static void _i2c_init(I2C_TypeDef *i2c, uint32_t timing)
{
    assert(i2c != NULL);

    /* disable device */
    i2c->CR1 &= ~(I2C_CR1_PE);

    /* configure analog noise filter */
    i2c->CR1 |= I2C_CR1_ANFOFF;

    /* configure digital noise filter */
    i2c->CR1 |= I2C_CR1_DNF;

    /* set timing registers */
    i2c->TIMINGR = timing;

    /* configure clock stretching */
    i2c->CR1 &= ~(I2C_CR1_NOSTRETCH);

    /* Clear interrupt */
    i2c->ICR |= CLEAR_FLAG;

    /* enable device */
    i2c->CR1 |= I2C_CR1_PE;
}

int i2c_acquire(i2c_t dev)
{
    assert(dev < I2C_NUMOF);

    mutex_lock(&locks[dev]);

    periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);

    return 0;
}

int i2c_release(i2c_t dev)
{
    assert(dev < I2C_NUMOF);

    periph_clk_dis(i2c_config[dev].bus, i2c_config[dev].rcc_mask);

    mutex_unlock(&locks[dev]);
    return 0;
}

int i2c_write_regs(i2c_t dev, uint16_t addr, uint16_t reg,
                   const void *data, size_t len, uint8_t flags)
{
    assert(dev < I2C_NUMOF);
    if (flags & (I2C_NOSTOP | I2C_NOSTART)) {
        return -EOPNOTSUPP;
    }

    I2C_TypeDef *i2c = i2c_config[dev].dev;
    assert(i2c != NULL);
    DEBUG("[i2c] write_regs: Starting\n");
    /* As a higher level function we know the bus should be free */
    if (i2c->ISR & I2C_ISR_BUSY) {
        return -EAGAIN;
    }
    /* First set ADDR and register with no stop */
    /* No RELOAD should be set so repeated start is valid */
    int ret = _write(i2c, addr, &reg, (flags & I2C_REG16) ? 2 : 1,
                     flags | I2C_NOSTOP, I2C_CR2_RELOAD);
    if (ret < 0) {<commit_msg>cpu/stm32: Fix 16 bit reg endianess for i2c_1<commit_after>/*
 * Copyright (C) 2015 <NAME> <<EMAIL>>
 *               2017 we-sens.com
 *               2018 Inria
 *               2018 HAW Hamburg
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @ingroup     cpu_stm32_common
 * @ingroup     drivers_periph_i2c
 * @{
 *
 * @file
 * @brief       Low-level I2C driver implementation
 *
 * This driver supports the STM32 F0, F3, F7, L0 and L4 families.
 * @note This implementation only implements the 7-bit addressing polling mode
 * (for now interrupt mode is not available)
 *
 * @author      <NAME> <peter.kietzmann@haw-hamburg.de>
 * @author      <NAME> <hauke.petersen@fu-berlin.de>
 * @auhtor      <NAME> <thomas.eichinger@fu-berlin.de>
 * @author      <NAME> <<EMAIL>>
 * @author      <NAME> <<EMAIL>>
 * @author      <NAME> <alexandre.abadie@inria.fr>
 * @author      <NAME> <kevin.weiss@haw-hamburg.de>
 *
 * @}
 */

#include <stdint.h>
#include <errno.h>

#include "cpu.h"
#include "mutex.h"
#include "byteorder.h"

#include "cpu_conf_stm32_common.h"

#include "periph/i2c.h"
#include "periph/gpio.h"
#include "periph_conf.h"

#define ENABLE_DEBUG    (0)
#include "debug.h"

#define TICK_TIMEOUT    (0xFFFF)
#define MAX_BYTES_PER_FRAME (256)

#define I2C_IRQ_PRIO    (1)
#define I2C_FLAG_READ   (I2C_READ << I2C_CR2_RD_WRN_Pos)
#define I2C_FLAG_WRITE  (0)

#define CLEAR_FLAG      (I2C_ICR_NACKCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ICR_ADDRCF)

/* static function definitions */
static inline void _i2c_init(I2C_TypeDef *i2c, uint32_t timing);
static int _write(I2C_TypeDef *i2c, uint16_t addr, const void *data,
                  size_t length, uint8_t flags, uint32_t cr2_flags);
static int _start(I2C_TypeDef *i2c, uint32_t cr2, uint8_t flags);
static int _stop(I2C_TypeDef *i2c);
static int _wait_isr_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags);
static inline int _wait_for_bus(I2C_TypeDef *i2c);

/**
 * @brief Array holding one pre-initialized mutex for each I2C device
 */
static mutex_t locks[I2C_NUMOF];

void i2c_init(i2c_t dev)
{
    assert(dev < I2C_NUMOF);

    DEBUG("[i2c] init: initializing device\n");
    mutex_init(&locks[dev]);

    I2C_TypeDef *i2c = i2c_config[dev].dev;

    periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);

    NVIC_SetPriority(i2c_config[dev].irqn, I2C_IRQ_PRIO);
    NVIC_EnableIRQ(i2c_config[dev].irqn);

#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
    /* Set I2CSW bits to enable I2C clock source */
    RCC->CFGR3 |= i2c_config[dev].rcc_sw_mask;
#endif

    DEBUG("[i2c] init: configuring pins\n");
    /* configure pins */
    gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU);
    gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af);
    gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU);
    gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af);

    DEBUG("[i2c] init: configuring device\n");
    /* set the timing register value from predefined values */
    i2c_timing_param_t tp = timing_params[i2c_config[dev].speed];
    uint32_t timing = (( (uint32_t)tp.presc << I2C_TIMINGR_PRESC_Pos) |
                       ( (uint32_t)tp.scldel << I2C_TIMINGR_SCLDEL_Pos) |
                       ( (uint32_t)tp.sdadel << I2C_TIMINGR_SDADEL_Pos) |
                       ( (uint16_t)tp.sclh << I2C_TIMINGR_SCLH_Pos) |
                       tp.scll);
    _i2c_init(i2c, timing);
}

static void _i2c_init(I2C_TypeDef *i2c, uint32_t timing)
{
    assert(i2c != NULL);

    /* disable device */
    i2c->CR1 &= ~(I2C_CR1_PE);

    /* configure analog noise filter */
    i2c->CR1 |= I2C_CR1_ANFOFF;

    /* configure digital noise filter */
    i2c->CR1 |= I2C_CR1_DNF;

    /* set timing registers */
    i2c->TIMINGR = timing;

    /* configure clock stretching */
    i2c->CR1 &= ~(I2C_CR1_NOSTRETCH);

    /* Clear interrupt */
    i2c->ICR |= CLEAR_FLAG;

    /* enable device */
    i2c->CR1 |= I2C_CR1_PE;
}

int i2c_acquire(i2c_t dev)
{
    assert(dev < I2C_NUMOF);

    mutex_lock(&locks[dev]);

    periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);

    return 0;
}

int i2c_release(i2c_t dev)
{
    assert(dev < I2C_NUMOF);

    periph_clk_dis(i2c_config[dev].bus, i2c_config[dev].rcc_mask);

    mutex_unlock(&locks[dev]);
    return 0;
}

int i2c_write_regs(i2c_t dev, uint16_t addr, uint16_t reg,
                   const void *data, size_t len, uint8_t flags)
{
    assert(dev < I2C_NUMOF);
    if (flags & (I2C_NOSTOP | I2C_NOSTART)) {
        return -EOPNOTSUPP;
    }

    I2C_TypeDef *i2c = i2c_config[dev].dev;
    assert(i2c != NULL);
    DEBUG("[i2c] write_regs: Starting\n");
    /* As a higher level function we know the bus should be free */
    if (i2c->ISR & I2C_ISR_BUSY) {
        return -EAGAIN;
    }
    /* Handle endianess of register if 16 bit */
    if (flags & I2C_REG16) {
        reg = htons(reg); /* Make sure register is in big-endian on I2C bus */
    }
    /* First set ADDR and register with no stop */
    /* No RELOAD should be set so repeated start is valid */
    int ret = _write(i2c, addr, &reg, (flags & I2C_REG16) ? 2 : 1,
                     flags | I2C_NOSTOP, I2C_CR2_RELOAD);
    if (ret < 0) {
{'fraction_non_alphanumeric': 0.12459111025591688, 'fraction_numerical': 0.038676159322686164, 'mean_word_length': 3.1546762589928057, 'pattern_counts': {'":': 0, '<': 74, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 11, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6414842', 'n_tokens_mistral': 4417, 'n_tokens_neox': 4212, 'n_words': 878}