<commit_before>/*
 * Copyright (C) 2015 Loci Controls Inc.
 *
 * 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_cc2538
 * @ingroup     drivers_periph
 * @{
 *
 * @file
 * @brief       Low-level I2C driver implementation
 *
 * @author      <NAME> <<EMAIL>>
 *
 * @}
 */

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>

#include "mutex.h"
#include "cpu.h"
#include "periph/i2c.h"
#include "thread.h"
#ifdef MODULE_XTIMER
#include "xtimer.h"
#endif
#include "timex.h" /* for US_PER_SEC */

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

/* guard this file in case no I2C device is defined */
#if I2C_NUMOF

#ifndef I2C_0_SCL_PIN
#define I2C_0_SCL_PIN i2c_config[I2C_0].scl_pin
#endif

#ifndef I2C_0_SDA_PIN
#define I2C_0_SDA_PIN i2c_config[I2C_0].sda_pin
#endif

#undef BIT
#define BIT(n)     ( 1 << (n) )

/* Standard I2C Parameters */
#define DATA_BITS  8
#define ACK_BITS   1

/* I2CM_DR Bits */
#define RS         BIT(0)

/* I2CM_CTRL Bits */
#define ACK        BIT(3)
#define STOP       BIT(2)
#define START      BIT(1)
#define RUN        BIT(0)

/* I2CM_STAT Bits */
#define BUSBSY     BIT(6)
#define IDLE       BIT(5)
#define ARBLST     BIT(4)
#define DATACK     BIT(3)
#define ADRACK     BIT(2)
#define ERROR      BIT(1)
#define BUSY       BIT(0)

/* I2CM_CR Bits */
#define SFE        BIT(5)
#define MFE        BIT(4)
#define LPBK       BIT(0)

#define ANY_ERROR  (ARBLST | DATACK | ADRACK | ERROR)

#define SCL_LP     6 /**< SCL Low Period (fixed at 6). */
#define SCL_HP     4 /**< SCL High Period (fixed at 4). */

static mutex_t mutex = MUTEX_INIT;
static mutex_t i2c_wait_mutex = MUTEX_INIT;
static uint32_t speed_hz;
static uint32_t scl_delay;

#define bus_quiet()            ( cc2538_gpio_read(I2C_0_SCL_PIN) && cc2538_gpio_read(I2C_0_SDA_PIN) )
#define WARN_IF(cond) \
        if (cond) { \
            DEBUG("%s at %s:%u\n", #cond, RIOT_FILE_NOPATH, __LINE__); \
        }

void cc2538_i2c_init_master(uint32_t speed_hz);

static void i2cm_ctrl_write(uint_fast8_t value) {
    WARN_IF(I2CM_STAT & BUSY);
    I2CM_CTRL = value;
}

static void assert_scl(void) {
    cc2538_gpio_clear(I2C_0_SCL_PIN);
    IOC_PXX_OVER[I2C_0_SCL_PIN] |= IOC_OVERRIDE_OE;
    gpio_dir_output(I2C_0_SCL_PIN);
    gpio_software_control(I2C_0_SCL_PIN);
}

static void release_scl(void) {
    IOC_PXX_OVER[I2C_0_SCL_PIN] &= ~(IOC_OVERRIDE_OE | IOC_OVERRIDE_PDE);
    gpio_dir_input(I2C_0_SCL_PIN);
    gpio_software_control(I2C_0_SCL_PIN);
}

static void release_sda(void) {
    IOC_PXX_OVER[I2C_0_SDA_PIN] &= ~(IOC_OVERRIDE_OE | IOC_OVERRIDE_PDE);
    gpio_dir_input(I2C_0_SDA_PIN);
    gpio_software_control(I2C_0_SDA_PIN);
}

static void recover_i2c_bus(void) {
    /* Switch to software GPIO mode for bus recovery */
    release_sda();
    release_scl();

    if (!bus_quiet()) {
        const uint_fast8_t try_limit = 200;
        uint_fast8_t n;
        for (n = 0; n < try_limit; n++) {
            if (bus_quiet()) {
                DEBUG("%s(): SDA released after%4u SCL pulses.\n", __FUNCTION__, n);
                break;
            }

            assert_scl();

#ifdef MODULE_XTIMER
            xtimer_usleep(scl_delay);
#else
            thread_yield();
#endif

            release_scl();

#ifdef MODULE_XTIMER
            xtimer_usleep(scl_delay);
#else
            thread_yield();
#endif
        }

        if (n >= try_limit) {
            DEBUG("%s(): Failed to release SDA after%4u SCL pulses.\n", __FUNCTION__, n);
        }
    }

    /* Return to hardware mode for the I2C pins */
    gpio_hardware_control(I2C_0_SCL_PIN);
    gpio_hardware_control(I2C_0_SDA_PIN);
}

#ifdef MODULE_XTIMER
static void callback(void *arg)
{
    mutex_unlock(&i2c_wait_mutex);
}
#endif

static uint_fast8_t i2c_ctrl_blocking(uint_fast8_t flags)
{
#ifdef MODULE_XTIMER
    const unsigned int xtimer_timeout = 3 * (DATA_BITS + ACK_BITS) * US_PER_SEC / speed_hz;
#endif

    mutex_trylock(&i2c_wait_mutex);

    assert(I2CM_IMR & 1);
    i2cm_ctrl_write(flags);

#ifdef MODULE_XTIMER
    /* Set a timeout at double the expected time to transmit a byte: */
    xtimer_t xtimer = {.callback = callback};
    xtimer_set(&xtimer, xtimer_timeout);
#endif

    mutex_lock(&i2c_wait_mutex);

#ifdef MODULE_XTIMER
    xtimer_remove(&xtimer);
#endif

    if (I2CM_STAT & BUSY) {
        /* If the controller is still busy, it probably will be forever */
#ifdef MODULE_XTIMER
        DEBUG("Master is still BUSY after %u usec. Resetting.\n", xtimer_timeout);
#endif
        cc2538_i2c_init_master(speed_hz);
    }

    WARN_IF(I2CM_STAT & BUSY);<commit_msg>cc2538: fix cppcheck warning in periph i2c driver<commit_after>/*
 * Copyright (C) 2015 Loci Controls Inc.
 *
 * 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_cc2538
 * @ingroup     drivers_periph
 * @{
 *
 * @file
 * @brief       Low-level I2C driver implementation
 *
 * @author      <NAME> <<EMAIL>>
 *
 * @}
 */

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>

#include "mutex.h"
#include "cpu.h"
#include "periph/i2c.h"
#include "thread.h"
#ifdef MODULE_XTIMER
#include "xtimer.h"
#endif
#include "timex.h" /* for US_PER_SEC */

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

/* guard this file in case no I2C device is defined */
#if I2C_NUMOF

#ifndef I2C_0_SCL_PIN
#define I2C_0_SCL_PIN i2c_config[I2C_0].scl_pin
#endif

#ifndef I2C_0_SDA_PIN
#define I2C_0_SDA_PIN i2c_config[I2C_0].sda_pin
#endif

#undef BIT
#define BIT(n)     ( 1 << (n) )

/* Standard I2C Parameters */
#define DATA_BITS  8
#define ACK_BITS   1

/* I2CM_DR Bits */
#define RS         BIT(0)

/* I2CM_CTRL Bits */
#define ACK        BIT(3)
#define STOP       BIT(2)
#define START      BIT(1)
#define RUN        BIT(0)

/* I2CM_STAT Bits */
#define BUSBSY     BIT(6)
#define IDLE       BIT(5)
#define ARBLST     BIT(4)
#define DATACK     BIT(3)
#define ADRACK     BIT(2)
#define ERROR      BIT(1)
#define BUSY       BIT(0)

/* I2CM_CR Bits */
#define SFE        BIT(5)
#define MFE        BIT(4)
#define LPBK       BIT(0)

#define ANY_ERROR  (ARBLST | DATACK | ADRACK | ERROR)

#define SCL_LP     6 /**< SCL Low Period (fixed at 6). */
#define SCL_HP     4 /**< SCL High Period (fixed at 4). */

static mutex_t mutex = MUTEX_INIT;
static mutex_t i2c_wait_mutex = MUTEX_INIT;
static uint32_t speed_hz;
static uint32_t scl_delay;

#define bus_quiet()            ( cc2538_gpio_read(I2C_0_SCL_PIN) && cc2538_gpio_read(I2C_0_SDA_PIN) )
#define WARN_IF(cond) \
        if (cond) { \
            DEBUG("%s at %s:%u\n", #cond, RIOT_FILE_NOPATH, __LINE__); \
        }

void cc2538_i2c_init_master(uint32_t speed_hz);

static void i2cm_ctrl_write(uint_fast8_t value) {
    WARN_IF(I2CM_STAT & BUSY);
    I2CM_CTRL = value;
}

static void assert_scl(void) {
    cc2538_gpio_clear(I2C_0_SCL_PIN);
    IOC_PXX_OVER[I2C_0_SCL_PIN] |= IOC_OVERRIDE_OE;
    gpio_dir_output(I2C_0_SCL_PIN);
    gpio_software_control(I2C_0_SCL_PIN);
}

static void release_scl(void) {
    IOC_PXX_OVER[I2C_0_SCL_PIN] &= ~(IOC_OVERRIDE_OE | IOC_OVERRIDE_PDE);
    gpio_dir_input(I2C_0_SCL_PIN);
    gpio_software_control(I2C_0_SCL_PIN);
}

static void release_sda(void) {
    IOC_PXX_OVER[I2C_0_SDA_PIN] &= ~(IOC_OVERRIDE_OE | IOC_OVERRIDE_PDE);
    gpio_dir_input(I2C_0_SDA_PIN);
    gpio_software_control(I2C_0_SDA_PIN);
}

static void recover_i2c_bus(void) {
    /* Switch to software GPIO mode for bus recovery */
    release_sda();
    release_scl();

    if (!bus_quiet()) {
        const uint_fast8_t try_limit = 200;
        uint_fast8_t n;
        for (n = 0; n < try_limit; n++) {
            if (bus_quiet()) {
                DEBUG("%s(): SDA released after%4u SCL pulses.\n", __FUNCTION__, n);
                break;
            }

            assert_scl();

#ifdef MODULE_XTIMER
            xtimer_usleep(scl_delay);
#else
            thread_yield();
#endif

            release_scl();

#ifdef MODULE_XTIMER
            xtimer_usleep(scl_delay);
#else
            thread_yield();
#endif
        }

        if (n >= try_limit) {
            DEBUG("%s(): Failed to release SDA after%4u SCL pulses.\n", __FUNCTION__, n);
        }
    }

    /* Return to hardware mode for the I2C pins */
    gpio_hardware_control(I2C_0_SCL_PIN);
    gpio_hardware_control(I2C_0_SDA_PIN);
}

#ifdef MODULE_XTIMER
static void _timer_cb(void *arg)
{
    mutex_unlock(&i2c_wait_mutex);
}
#endif

static uint_fast8_t i2c_ctrl_blocking(uint_fast8_t flags)
{
#ifdef MODULE_XTIMER
    const unsigned int xtimer_timeout = 3 * (DATA_BITS + ACK_BITS) * US_PER_SEC / speed_hz;
#endif

    mutex_trylock(&i2c_wait_mutex);

    assert(I2CM_IMR & 1);
    i2cm_ctrl_write(flags);

#ifdef MODULE_XTIMER
    /* Set a timeout at double the expected time to transmit a byte: */
    xtimer_t xtimer = { .callback = _timer_cb, .arg = NULL };
    xtimer_set(&xtimer, xtimer_timeout);
#endif

    mutex_lock(&i2c_wait_mutex);

#ifdef MODULE_XTIMER
    xtimer_remove(&xtimer);
#endif

    if (I2CM_STAT & BUSY) {
        /* If the controller is still busy, it probably will be forever */
#ifdef MODULE_XTIMER
        DEBUG("Master is still BUSY after %u usec. Resetting.\n", xtimer_timeout);
#endif
        cc2538_i2c_init_master(speed_hz);
    }

    WARN_IF(I2CM_STAT & BUSY);
{'fraction_non_alphanumeric': 0.11297291600800928, 'fraction_numerical': 0.0298240067446517, 'mean_word_length': 3.118923611111111, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '2607076', 'n_tokens_mistral': 3969, 'n_tokens_neox': 3800, 'n_words': 840}