2375 lines
78 KiB
C
2375 lines
78 KiB
C
|
/***************************************************************************
|
||
|
*
|
||
|
* Copyright 2015-2019 BES.
|
||
|
* All rights reserved. All unpublished rights reserved.
|
||
|
*
|
||
|
* No part of this work may be used or reproduced in any form or by any
|
||
|
* means, or stored in a database or retrieval system, without prior written
|
||
|
* permission of BES.
|
||
|
*
|
||
|
* Use of this work is governed by a license granted by BES.
|
||
|
* This work contains confidential and proprietary information of
|
||
|
* BES. which is protected by copyright, trade secret,
|
||
|
* trademark and other intellectual property rights.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
#include "plat_types.h"
|
||
|
#include "plat_addr_map.h"
|
||
|
#include "string.h"
|
||
|
#include "hal_i2c.h"
|
||
|
#include "hal_i2cip.h"
|
||
|
#include "hal_timer.h"
|
||
|
#include "hal_dma.h"
|
||
|
#include "hal_trace.h"
|
||
|
#include "hal_cmu.h"
|
||
|
#include "cmsis_nvic.h"
|
||
|
#ifdef RTOS
|
||
|
#include "cmsis_os.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef I2C_DEBUG
|
||
|
#define HAL_I2C_TRACE(attr, str, ...) TRACE(attr, str, ##__VA_ARGS__)
|
||
|
#define HAL_I2C_ERROR(attr, str, ...) TRACE(attr, str, ##__VA_ARGS__)
|
||
|
#else
|
||
|
#define HAL_I2C_TRACE(attr, str, ...) TRACE_DUMMY(attr, str, ##__VA_ARGS__)
|
||
|
#define HAL_I2C_ERROR(attr, str, ...) TRACE(attr, str, ##__VA_ARGS__)
|
||
|
#endif
|
||
|
|
||
|
#ifdef I2C_SENSOR_ENGINE
|
||
|
#ifndef I2C_USE_DMA
|
||
|
#define I2C_USE_DMA
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#define HAL_I2C_TX_TL I2CIP_TX_TL_QUARTER
|
||
|
#define HAL_I2C_RX_TL I2CIP_RX_TL_THREE_QUARTER
|
||
|
|
||
|
#define HAL_I2C_DMA_TX_TL I2CIP_TX_TL_HALF
|
||
|
#define HAL_I2C_DMA_RX_TL I2CIP_DMA_TX_TL_1_BYTE
|
||
|
|
||
|
#define HAL_I2C_DMA_TX 1
|
||
|
#define HAL_I2C_DMA_RX 0
|
||
|
|
||
|
#define HAL_I2C_RESTART 1
|
||
|
#define HAL_I2C_NO_RESTART 0
|
||
|
|
||
|
#define HAL_I2C_YES 1
|
||
|
#define HAL_I2C_NO 0
|
||
|
|
||
|
/* state machine */
|
||
|
#ifdef I2C_SM_TASK_NUM
|
||
|
#define HAL_I2C_SM_TASK_NUM_MAX I2C_SM_TASK_NUM
|
||
|
#else
|
||
|
#define HAL_I2C_SM_TASK_NUM_MAX 2
|
||
|
#endif
|
||
|
|
||
|
#ifdef I2C_SM_DMA_BUF_SIZE
|
||
|
#define HAL_I2C_SM_DMA_BUF_LEN_MAX I2C_SM_DMA_BUF_SIZE
|
||
|
#else
|
||
|
#define HAL_I2C_SM_DMA_BUF_LEN_MAX 1024
|
||
|
#endif
|
||
|
|
||
|
/* i2c synchronization timeout ms */
|
||
|
#define HAL_I2C_SYNC_TM_MS (2000)
|
||
|
#define HAL_I2C_DLY_MS (1)
|
||
|
#define HAL_I2C_WAIT_ACT_MS (1000)
|
||
|
#define HAL_I2C_WAIT_TFE_MS (1000)
|
||
|
#define HAL_I2C_WAIT_TFNF_MS (1000)
|
||
|
#define HAL_I2C_WAIT_RFNE_MS (1000)
|
||
|
|
||
|
enum HAL_I2C_SM_STATE_T {
|
||
|
HAL_I2C_SM_CLOSED = 0,
|
||
|
HAL_I2C_SM_IDLE,
|
||
|
HAL_I2C_SM_RUNNING,
|
||
|
};
|
||
|
|
||
|
enum HAL_I2C_SM_TASK_ACTION_T {
|
||
|
HAL_I2C_SM_TASK_ACTION_NONE = 0,
|
||
|
HAL_I2C_SM_TASK_ACTION_M_SEND,
|
||
|
HAL_I2C_SM_TASK_ACTION_M_RECV,
|
||
|
};
|
||
|
|
||
|
enum HAL_I2C_SM_TASK_STATE_T {
|
||
|
HAL_I2C_SM_TASK_STATE_START = (1 << 0),
|
||
|
HAL_I2C_SM_TASK_STATE_STOP = (1 << 1),
|
||
|
HAL_I2C_SM_TASK_STATE_TX_ABRT = (1 << 2),
|
||
|
HAL_I2C_SM_TASK_STATE_ACT = (1 << 3),
|
||
|
HAL_I2C_SM_TASK_STATE_FIFO_ERR = (1 << 4),
|
||
|
};
|
||
|
|
||
|
struct HAL_I2C_SM_TASK_T {
|
||
|
/* send or recv buffer */
|
||
|
const uint8_t *tx_buf;
|
||
|
uint8_t *rx_buf;
|
||
|
uint16_t tx_txn_len;
|
||
|
uint16_t rx_txn_len;
|
||
|
uint16_t txn_cnt;
|
||
|
uint16_t tx_pos;
|
||
|
uint16_t rx_pos;
|
||
|
uint16_t rx_cmd_sent;
|
||
|
|
||
|
/* device control */
|
||
|
uint8_t stop;
|
||
|
uint8_t restart_after_write;
|
||
|
uint16_t target_addr;
|
||
|
|
||
|
/* task control */
|
||
|
uint32_t state;
|
||
|
uint32_t action;
|
||
|
|
||
|
/* system control */
|
||
|
/* TODO : os and non os version */
|
||
|
volatile uint32_t lock;
|
||
|
uint32_t transfer_id;
|
||
|
uint32_t errcode;
|
||
|
HAL_I2C_TRANSFER_HANDLER_T handler;
|
||
|
};
|
||
|
|
||
|
struct HAL_I2C_SM_T {
|
||
|
/* device related */
|
||
|
struct HAL_I2C_CONFIG_T cfg;
|
||
|
|
||
|
enum HAL_I2C_SM_STATE_T state;
|
||
|
|
||
|
/* state machine related */
|
||
|
#if defined(I2C_TASK_MODE) || defined(I2C_SENSOR_ENGINE)
|
||
|
uint8_t in_task;
|
||
|
uint8_t out_task;
|
||
|
uint8_t task_count;
|
||
|
struct HAL_I2C_SM_TASK_T task[HAL_I2C_SM_TASK_NUM_MAX];
|
||
|
|
||
|
/* dma related */
|
||
|
#ifdef I2C_USE_DMA
|
||
|
struct HAL_DMA_CH_CFG_T tx_dma_cfg;
|
||
|
struct HAL_DMA_CH_CFG_T rx_dma_cfg;
|
||
|
/* i2cip cmd_data use 16bit and read action is driven by write action */
|
||
|
/* when use dma to read from i2c, we need to use another dma to write cmd/stop/restart */
|
||
|
/* cmd/stop/restart + data use 16bit width, so dma buffer are 2 times of orgin data buffer */
|
||
|
uint16_t dma_tx_buf[HAL_I2C_SM_DMA_BUF_LEN_MAX / 2];
|
||
|
#endif
|
||
|
#endif
|
||
|
};
|
||
|
/* state machine end */
|
||
|
|
||
|
struct HAL_I2C_MOD_NAME_T {
|
||
|
};
|
||
|
|
||
|
struct HAL_I2C_HW_DESC_T {
|
||
|
uint32_t base;
|
||
|
enum HAL_CMU_MOD_ID_T mod;
|
||
|
enum HAL_CMU_MOD_ID_T apb;
|
||
|
IRQn_Type irq;
|
||
|
#ifdef I2C_USE_DMA
|
||
|
enum HAL_DMA_PERIPH_T rx_periph;
|
||
|
enum HAL_DMA_PERIPH_T tx_periph;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
static const struct HAL_I2C_HW_DESC_T i2c_desc[HAL_I2C_ID_NUM] = {
|
||
|
{
|
||
|
.base = I2C0_BASE,
|
||
|
.mod = HAL_CMU_MOD_O_I2C0,
|
||
|
.apb = HAL_CMU_MOD_P_I2C0,
|
||
|
.irq = I2C0_IRQn,
|
||
|
#ifdef I2C_USE_DMA
|
||
|
.rx_periph = HAL_GPDMA_I2C0_RX,
|
||
|
.tx_periph = HAL_GPDMA_I2C0_TX,
|
||
|
#endif
|
||
|
},
|
||
|
#if (CHIP_HAS_I2C > 1)
|
||
|
{
|
||
|
.base = I2C1_BASE,
|
||
|
.mod = HAL_CMU_MOD_O_I2C1,
|
||
|
.apb = HAL_CMU_MOD_P_I2C1,
|
||
|
.irq = I2C1_IRQn,
|
||
|
#ifdef I2C_USE_DMA
|
||
|
.rx_periph = HAL_GPDMA_I2C1_RX,
|
||
|
.tx_periph = HAL_GPDMA_I2C1_TX,
|
||
|
#endif
|
||
|
},
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
static const char * const invalid_id = "Invalid I2C ID: %d";
|
||
|
|
||
|
static struct HAL_I2C_SM_T hal_i2c_sm[HAL_I2C_ID_NUM];
|
||
|
|
||
|
/* simple mode */
|
||
|
#ifdef I2C_SIMPLE_MODE
|
||
|
static void hal_i2c_simple_proc(enum HAL_I2C_ID_T id);
|
||
|
|
||
|
static HAL_I2C_INT_HANDLER_T hal_i2c_int_handlers[HAL_I2C_ID_NUM] = {NULL};
|
||
|
#endif
|
||
|
/* simple mode end */
|
||
|
|
||
|
#ifdef I2C_SENSOR_ENGINE
|
||
|
static enum HAL_SENSOR_ENGINE_ID_T i2c_sensor_id[HAL_I2C_ID_NUM];
|
||
|
static HAL_I2C_SENSOR_ENG_HANDLER_T i2c_sensor_handler[HAL_I2C_ID_NUM];
|
||
|
|
||
|
#ifdef I2C_SENSOR_ENGINE
|
||
|
static void hal_i2c_sensor_eng_proc(enum HAL_I2C_ID_T id);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
static uint32_t _i2c_get_base(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
return i2c_desc[id].base;
|
||
|
}
|
||
|
|
||
|
static void POSSIBLY_UNUSED hal_i2c_delay_ms(int ms)
|
||
|
{
|
||
|
osDelay(ms);
|
||
|
}
|
||
|
|
||
|
static uint32_t _i2c_adjust_period_cnt(uint32_t period_cnt, uint16_t trising_ns, uint16_t tfalling_ns, uint16_t pclk_mhz)
|
||
|
{
|
||
|
uint32_t old_period_cnt;
|
||
|
uint16_t rising_falling_cycle;
|
||
|
|
||
|
old_period_cnt = period_cnt;
|
||
|
|
||
|
// Round down the rising and falling cycle, so that the period count is rounded up,
|
||
|
// and the SCL freq is always <= the requested freq.
|
||
|
rising_falling_cycle = ((trising_ns + tfalling_ns) * pclk_mhz) / 1000;
|
||
|
|
||
|
if (period_cnt > rising_falling_cycle) {
|
||
|
period_cnt -= rising_falling_cycle;
|
||
|
} else {
|
||
|
period_cnt = 0;
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(5,"%s: period_cnt=%u->%u trising_ns=%u tfalling_ns=%u",
|
||
|
__FUNCTION__, old_period_cnt, period_cnt, trising_ns, tfalling_ns);
|
||
|
|
||
|
return period_cnt;
|
||
|
}
|
||
|
|
||
|
static void _i2c_get_clk_cnt(uint32_t period_cnt, uint16_t tlow_ns, uint16_t thigh_ns, uint16_t spklen,
|
||
|
uint16_t pclk_mhz, uint16_t *plcnt, uint16_t *phcnt)
|
||
|
{
|
||
|
#define IC_SCL_LOW_CYCLE_ADD (1)
|
||
|
// NOTE: H/w spec says that (6 + spklen) cycles is added for SCL high interval, but tests show that 1 more cycle is needed
|
||
|
#define IC_SCL_HIGH_CYCLE_ADD (6 + spklen + 1)
|
||
|
|
||
|
#define MIN_IC_SCL_LCNT (7 + spklen + IC_SCL_LOW_CYCLE_ADD)
|
||
|
#define MIN_IC_SCL_HCNT (5 + spklen + IC_SCL_HIGH_CYCLE_ADD)
|
||
|
|
||
|
uint32_t lcnt, hcnt;
|
||
|
uint16_t min_lcnt, min_hcnt;
|
||
|
|
||
|
HAL_I2C_TRACE(6,"%s: period_cnt=%u tlow_ns=%u thigh_ns=%u spklen=%u pclk_mhz=%u",
|
||
|
__FUNCTION__, period_cnt, tlow_ns, thigh_ns, spklen, pclk_mhz);
|
||
|
|
||
|
min_lcnt = (tlow_ns * pclk_mhz + 1000 - 1) / 1000;
|
||
|
if (min_lcnt < MIN_IC_SCL_LCNT) {
|
||
|
min_lcnt = MIN_IC_SCL_LCNT;
|
||
|
}
|
||
|
min_hcnt = (thigh_ns * pclk_mhz + 1000 - 1) / 1000;
|
||
|
if (min_hcnt < MIN_IC_SCL_HCNT) {
|
||
|
min_hcnt = MIN_IC_SCL_HCNT;
|
||
|
}
|
||
|
|
||
|
if (min_lcnt + min_hcnt > period_cnt) {
|
||
|
HAL_I2C_ERROR(5,"%s:WARNING: period_cnt=%u too small: min_lcnt=%u min_hcnt=%u pclk_mhz=%u",
|
||
|
__FUNCTION__, period_cnt, min_lcnt, min_hcnt, pclk_mhz);
|
||
|
|
||
|
lcnt = min_lcnt;
|
||
|
hcnt = min_hcnt;
|
||
|
} else {
|
||
|
lcnt = (period_cnt + 1) / 2;
|
||
|
if (min_lcnt >= min_hcnt) {
|
||
|
if (lcnt < min_lcnt) {
|
||
|
lcnt = min_lcnt;
|
||
|
}
|
||
|
hcnt = period_cnt - lcnt;
|
||
|
if (hcnt < min_hcnt) {
|
||
|
hcnt = min_hcnt;
|
||
|
}
|
||
|
} else {
|
||
|
hcnt = lcnt;
|
||
|
if (hcnt < min_hcnt) {
|
||
|
hcnt = min_hcnt;
|
||
|
}
|
||
|
lcnt = period_cnt - hcnt;
|
||
|
if (lcnt < min_lcnt) {
|
||
|
lcnt = min_lcnt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lcnt -= IC_SCL_LOW_CYCLE_ADD;
|
||
|
hcnt -= IC_SCL_HIGH_CYCLE_ADD;
|
||
|
|
||
|
ASSERT(lcnt <= UINT16_MAX && hcnt <= UINT16_MAX, "%s: lcnt=%u or hcnt=%u overflow", __FUNCTION__, lcnt, hcnt);
|
||
|
|
||
|
*plcnt = lcnt;
|
||
|
*phcnt = hcnt;
|
||
|
}
|
||
|
|
||
|
static void _i2c_set_speed(enum HAL_I2C_ID_T id, int speed_mode, int speed)
|
||
|
{
|
||
|
#define MAX_HS_SPK_NS 10
|
||
|
#define MAX_FSP_SPK_NS 50
|
||
|
#define MAX_FS_SPK_NS 50
|
||
|
|
||
|
#define SS_THOLD_NS 1800 // [300, 3450]
|
||
|
#define FS_THOLD_NS 600 // [300, 900]
|
||
|
#define FSP_THOLD_NS 300 // [ 0, -]
|
||
|
#define HS_100PF_THOLD_NS 30 // [ 0, 70]
|
||
|
#define HS_400PF_THOLD_NS 70 // [ 0, 150]
|
||
|
|
||
|
#define SS_TRISING_NS 300 // [ 0, 1000]
|
||
|
#define FS_TRISING_NS 50 // [ 20, 300]
|
||
|
#define FSP_TRISING_NS 30 // [ 0, 120]
|
||
|
#define HS_100PF_TRISING_NS 30 // [ 10, 40] for SCL, [ 20, 80] for SDA
|
||
|
#define HS_400PF_TRISING_NS 30 // [ 10, 80] for SCL, [ 20, 160] for SDA
|
||
|
|
||
|
#define SS_TFALLING_NS 30 // [ 0, 300]
|
||
|
#define FS_TFALLING_NS 30 // [ 20, 300]
|
||
|
#define FSP_TFALLING_NS 30 // [ 20, 120]
|
||
|
#define HS_100PF_TFALLING_NS 30 // [ 10, 40] for SCL, [ 20, 80] for SDA
|
||
|
#define HS_400PF_TFALLING_NS 30 // [ 10, 80] for SCL, [ 20, 160] for SDA
|
||
|
|
||
|
#define MIN_SS_TLOW_NS 4700
|
||
|
#define MIN_SS_THIGH_NS 4000
|
||
|
#define MIN_FS_TLOW_NS 1300
|
||
|
#define MIN_FS_THIGH_NS 600
|
||
|
#define MIN_FSP_TLOW_NS 500
|
||
|
#define MIN_FSP_THIGH_NS 260
|
||
|
#define MIN_HS_100PF_TLOW_NS 160
|
||
|
#define MIN_HS_100PF_THIGH_NS 60
|
||
|
#define MIN_HS_400PF_TLOW_NS 320
|
||
|
#define MIN_HS_400PF_THIGH_NS 120
|
||
|
|
||
|
// Round down the spike suppression limit value
|
||
|
#define GET_SPKLEN_VAL(s) ((s) * pclk_mhz / 1000)
|
||
|
|
||
|
uint32_t reg_base = _i2c_get_base(id);
|
||
|
uint32_t min_mclk, pclk, period_cnt;
|
||
|
uint16_t lcnt, hcnt, hold_cycle, spklen;
|
||
|
uint16_t tlow_ns, thigh_ns, thold_ns, trising_ns, tfalling_ns;
|
||
|
uint8_t spk_ns;
|
||
|
uint16_t pclk_mhz;
|
||
|
|
||
|
if (speed_mode == IC_SPEED_MODE_MAX) {
|
||
|
min_mclk = speed * 50;
|
||
|
} else {
|
||
|
min_mclk = speed * 40;
|
||
|
}
|
||
|
pclk = 0;
|
||
|
#ifdef PERIPH_PLL_FREQ
|
||
|
if (PERIPH_PLL_FREQ / 2 > 2 * hal_cmu_get_crystal_freq()) {
|
||
|
// Init to OSC_X2
|
||
|
pclk = 2 * hal_cmu_get_crystal_freq();
|
||
|
if (min_mclk > pclk) {
|
||
|
pclk = PERIPH_PLL_FREQ / 2;
|
||
|
hal_cmu_i2c_set_div(2);
|
||
|
} else {
|
||
|
pclk = 0;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
if (pclk == 0) {
|
||
|
enum HAL_CMU_PERIPH_FREQ_T periph_freq;
|
||
|
|
||
|
// Init to OSC
|
||
|
pclk = hal_cmu_get_crystal_freq();
|
||
|
if (min_mclk > pclk) {
|
||
|
pclk *= 2;
|
||
|
periph_freq = HAL_CMU_PERIPH_FREQ_52M;
|
||
|
} else {
|
||
|
periph_freq = HAL_CMU_PERIPH_FREQ_26M;
|
||
|
}
|
||
|
|
||
|
// NOTE: All I2C controllers share the same module clock configuration
|
||
|
hal_cmu_i2c_set_freq(periph_freq);
|
||
|
}
|
||
|
|
||
|
pclk_mhz = pclk / 1000000;
|
||
|
period_cnt = (pclk + speed - 1) / speed;
|
||
|
|
||
|
switch (speed_mode) {
|
||
|
case IC_SPEED_MODE_MAX:
|
||
|
|
||
|
spk_ns = MAX_HS_SPK_NS;
|
||
|
tlow_ns = MIN_HS_100PF_TLOW_NS;
|
||
|
thigh_ns = MIN_HS_100PF_THIGH_NS;
|
||
|
thold_ns = HS_100PF_THOLD_NS;
|
||
|
trising_ns = HS_100PF_TRISING_NS;
|
||
|
tfalling_ns = HS_100PF_TFALLING_NS;
|
||
|
|
||
|
spklen = GET_SPKLEN_VAL(spk_ns);
|
||
|
if (spklen == 0) {
|
||
|
spklen = 1;
|
||
|
}
|
||
|
i2cip_w_hs_spklen(reg_base, spklen);
|
||
|
|
||
|
period_cnt = _i2c_adjust_period_cnt(period_cnt, trising_ns, tfalling_ns, pclk_mhz);
|
||
|
_i2c_get_clk_cnt(period_cnt, tlow_ns, thigh_ns, spklen, pclk_mhz, &lcnt, &hcnt);
|
||
|
|
||
|
i2cip_w_high_speed_hcnt(reg_base, hcnt);
|
||
|
i2cip_w_high_speed_lcnt(reg_base, lcnt);
|
||
|
|
||
|
i2cip_w_speed(reg_base, I2CIP_HIGH_SPEED_MASK);
|
||
|
|
||
|
// Continue to config fast mode
|
||
|
#ifdef I2S_FSP_MODE
|
||
|
period_cnt = (pclk + I2C_FSP_SPEED - 1) / I2C_FSP_SPEED;
|
||
|
#else
|
||
|
period_cnt = (pclk + I2C_FAST_SPEED - 1) / I2C_FAST_SPEED;
|
||
|
#endif
|
||
|
|
||
|
case IC_SPEED_MODE_FAST:
|
||
|
|
||
|
#ifdef I2S_FSP_MODE
|
||
|
if (speed > I2C_FAST_SPEED) {
|
||
|
spk_ns = MAX_FSP_SPK_NS;
|
||
|
tlow_ns = MIN_FSP_TLOW_NS;
|
||
|
thigh_ns = MIN_FSP_THIGH_NS;
|
||
|
thold_ns = FSP_THOLD_NS;
|
||
|
trising_ns = FSP_TRISING_NS;
|
||
|
tfalling_ns = FSP_TFALLING_NS;
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
spk_ns = MAX_FS_SPK_NS;
|
||
|
tlow_ns = MIN_FS_TLOW_NS;
|
||
|
thigh_ns = MIN_FS_THIGH_NS;
|
||
|
trising_ns = FS_TRISING_NS;
|
||
|
tfalling_ns = FS_TFALLING_NS;
|
||
|
}
|
||
|
|
||
|
spklen = GET_SPKLEN_VAL(spk_ns);
|
||
|
if (spklen == 0) {
|
||
|
spklen = 1;
|
||
|
}
|
||
|
i2cip_w_fs_spklen(reg_base, spklen);
|
||
|
|
||
|
period_cnt = _i2c_adjust_period_cnt(period_cnt, trising_ns, tfalling_ns, pclk_mhz);
|
||
|
_i2c_get_clk_cnt(period_cnt, tlow_ns, thigh_ns, spklen, pclk_mhz, &lcnt, &hcnt);
|
||
|
|
||
|
i2cip_w_fast_speed_hcnt(reg_base, hcnt);
|
||
|
i2cip_w_fast_speed_lcnt(reg_base, lcnt);
|
||
|
|
||
|
// Update sda hold time and speed mode if in fast mode
|
||
|
// Skip if in high speed mode
|
||
|
if (speed_mode == IC_SPEED_MODE_FAST) {
|
||
|
thold_ns = FS_THOLD_NS;
|
||
|
i2cip_w_speed(reg_base, I2CIP_FAST_SPEED_MASK);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case IC_SPEED_MODE_STANDARD:
|
||
|
default:
|
||
|
|
||
|
spk_ns = MAX_FS_SPK_NS;
|
||
|
tlow_ns = MIN_SS_TLOW_NS;
|
||
|
thigh_ns = MIN_SS_THIGH_NS;
|
||
|
thold_ns = SS_THOLD_NS;
|
||
|
trising_ns = SS_TRISING_NS;
|
||
|
tfalling_ns = SS_TFALLING_NS;
|
||
|
|
||
|
spklen = GET_SPKLEN_VAL(spk_ns);
|
||
|
if (spklen == 0) {
|
||
|
spklen = 1;
|
||
|
}
|
||
|
i2cip_w_fs_spklen(reg_base, spklen);
|
||
|
|
||
|
period_cnt = _i2c_adjust_period_cnt(period_cnt, trising_ns, tfalling_ns, pclk_mhz);
|
||
|
_i2c_get_clk_cnt(period_cnt, tlow_ns, thigh_ns, spklen, pclk_mhz, &lcnt, &hcnt);
|
||
|
|
||
|
i2cip_w_standard_speed_hcnt(reg_base, hcnt);
|
||
|
i2cip_w_standard_speed_lcnt(reg_base, lcnt);
|
||
|
i2cip_w_speed(reg_base, I2CIP_STANDARD_SPEED_MASK);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Master mode: min = 1; slave mode: min = (spklen + 7)
|
||
|
hold_cycle = (thold_ns * pclk_mhz + 1000 - 1) / 1000;
|
||
|
i2cip_w_sda_hold_time(reg_base, hold_cycle);
|
||
|
|
||
|
HAL_I2C_TRACE(1,"crystal freq=%d", pclk);
|
||
|
HAL_I2C_TRACE(5,"i2c-%d mode=%d lcnt=%d hcnt=%d hold=%d",
|
||
|
id, speed_mode, lcnt, hcnt, hold_cycle);
|
||
|
}
|
||
|
|
||
|
static uint8_t _i2c_set_bus_speed(enum HAL_I2C_ID_T id,
|
||
|
unsigned int speed)
|
||
|
{
|
||
|
uint32_t speed_mode;
|
||
|
|
||
|
if (speed > I2C_FSP_SPEED)
|
||
|
speed_mode = IC_SPEED_MODE_MAX;
|
||
|
else if (speed > I2C_FAST_SPEED)
|
||
|
#ifdef I2S_FSP_MODE
|
||
|
speed_mode = IC_SPEED_MODE_FAST;
|
||
|
#else
|
||
|
speed_mode = IC_SPEED_MODE_MAX;
|
||
|
#endif
|
||
|
else if (speed > I2C_STANDARD_SPEED)
|
||
|
speed_mode = IC_SPEED_MODE_FAST;
|
||
|
else
|
||
|
speed_mode = IC_SPEED_MODE_STANDARD;
|
||
|
|
||
|
_i2c_set_speed(id, speed_mode, speed);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* state machine related */
|
||
|
static void hal_i2c_sm_init(enum HAL_I2C_ID_T id, const struct HAL_I2C_CONFIG_T *cfg)
|
||
|
{
|
||
|
memcpy(&hal_i2c_sm[id].cfg, cfg, sizeof(*cfg));
|
||
|
hal_i2c_sm[id].state = HAL_I2C_SM_IDLE;
|
||
|
#if defined(I2C_TASK_MODE) || defined(I2C_SENSOR_ENGINE)
|
||
|
hal_i2c_sm[id].in_task = 0;
|
||
|
hal_i2c_sm[id].out_task = 0;
|
||
|
hal_i2c_sm[id].task_count = 0;
|
||
|
|
||
|
#ifdef I2C_USE_DMA
|
||
|
hal_i2c_sm[id].tx_dma_cfg.ch = HAL_DMA_CHAN_NONE;
|
||
|
hal_i2c_sm[id].rx_dma_cfg.ch = HAL_DMA_CHAN_NONE;
|
||
|
#else
|
||
|
hal_i2c_sm[id].cfg.use_dma = 0;
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if defined(I2C_TASK_MODE) || defined(I2C_SENSOR_ENGINE)
|
||
|
static uint32_t hal_i2c_sm_commit(enum HAL_I2C_ID_T id, const uint8_t *tx_buf, uint16_t tx_txn_len,
|
||
|
uint8_t *rx_buf, uint16_t rx_txn_len, uint16_t txn_cnt,
|
||
|
uint16_t target_addr, uint32_t action,
|
||
|
uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
uint32_t cur = hal_i2c_sm[id].in_task;
|
||
|
|
||
|
hal_i2c_sm[id].task[cur].tx_buf = tx_buf;
|
||
|
hal_i2c_sm[id].task[cur].rx_buf = rx_buf;
|
||
|
hal_i2c_sm[id].task[cur].stop = 1;
|
||
|
hal_i2c_sm[id].task[cur].lock = 1;
|
||
|
hal_i2c_sm[id].task[cur].state = 0;
|
||
|
hal_i2c_sm[id].task[cur].rx_txn_len = rx_txn_len;
|
||
|
hal_i2c_sm[id].task[cur].tx_txn_len = tx_txn_len;
|
||
|
hal_i2c_sm[id].task[cur].txn_cnt = txn_cnt;
|
||
|
hal_i2c_sm[id].task[cur].tx_pos = 0;
|
||
|
hal_i2c_sm[id].task[cur].rx_pos = 0;
|
||
|
hal_i2c_sm[id].task[cur].rx_cmd_sent = 0;
|
||
|
hal_i2c_sm[id].task[cur].errcode = 0;
|
||
|
hal_i2c_sm[id].task[cur].action = action;
|
||
|
hal_i2c_sm[id].task[cur].handler = handler;
|
||
|
hal_i2c_sm[id].task[cur].restart_after_write = 1;
|
||
|
hal_i2c_sm[id].task[cur].target_addr = target_addr;
|
||
|
hal_i2c_sm[id].task[cur].transfer_id = transfer_id;
|
||
|
|
||
|
hal_i2c_sm[id].in_task = (cur + 1) % HAL_I2C_SM_TASK_NUM_MAX;
|
||
|
hal_i2c_sm[id].task_count++;
|
||
|
return cur;
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_sm_done(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
hal_i2c_sm[id].in_task = 0;
|
||
|
hal_i2c_sm[id].out_task = 0;
|
||
|
hal_i2c_sm[id].task_count = 0;
|
||
|
hal_i2c_sm[id].state = HAL_I2C_SM_IDLE;
|
||
|
|
||
|
HAL_I2C_TRACE(1,"%s", __func__);
|
||
|
}
|
||
|
|
||
|
static enum HAL_I2C_SM_TASK_STATE_T _i2c_chk_clr_task_error(uint32_t reg_base, uint32_t ip_int_status, uint32_t tx_abrt_source)
|
||
|
{
|
||
|
enum HAL_I2C_SM_TASK_STATE_T state = 0;
|
||
|
uint32_t tmp1;
|
||
|
|
||
|
/* tx abort interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_TX_ABRT_MASK) {
|
||
|
state |= HAL_I2C_SM_TASK_STATE_TX_ABRT;
|
||
|
|
||
|
/* sbyte_norstrt is special to clear : restart disable but user want to send a restart */
|
||
|
/* to fix this bit : enable restart , clear speical , clear gc_or_start bit temporary */
|
||
|
tmp1 = i2cip_r_target_address_reg(reg_base);
|
||
|
if (tx_abrt_source & I2CIP_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT_MASK) {
|
||
|
i2cip_w_restart(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_special_bit(reg_base, HAL_I2C_NO);
|
||
|
i2cip_w_gc_or_start_bit(reg_base, HAL_I2C_NO);
|
||
|
}
|
||
|
i2cip_r_clr_tx_abrt(reg_base);
|
||
|
/* restore register after clear */
|
||
|
if (tx_abrt_source & I2CIP_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT_MASK) {
|
||
|
i2cip_w_target_address_reg(reg_base, tmp1);
|
||
|
}
|
||
|
}
|
||
|
/* tx overflow interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_MASK_TX_OVER_MASK) {
|
||
|
state |= HAL_I2C_SM_TASK_STATE_FIFO_ERR;
|
||
|
i2cip_r_clr_tx_over(reg_base);
|
||
|
}
|
||
|
/* rx overflow interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_MASK_RX_OVER_MASK) {
|
||
|
state |= HAL_I2C_SM_TASK_STATE_FIFO_ERR;
|
||
|
i2cip_r_clr_rx_over(reg_base);
|
||
|
}
|
||
|
/* rx underflow interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_MASK_RX_UNDER_MASK) {
|
||
|
state |= HAL_I2C_SM_TASK_STATE_FIFO_ERR;
|
||
|
i2cip_r_clr_rx_under(reg_base);
|
||
|
}
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
static void _i2c_show_error_code(uint32_t errcode)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
if (errcode & HAL_I2C_ERRCODE_SLVRD_INTX)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_SLVRD_INTX");
|
||
|
if (errcode & HAL_I2C_ERRCODE_SLV_ARBLOST)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_SLV_ARBLOST");
|
||
|
if (errcode & HAL_I2C_ERRCODE_SLVFLUSH_TXFIFO)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_SLVFLUSH_TXFIFO");
|
||
|
if (errcode & HAL_I2C_ERRCODE_MASTER_DIS)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_MASTER_DIS");
|
||
|
if (errcode & HAL_I2C_ERRCODE_10B_RD_NORSTRT)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_10B_RD_NORSTRT");
|
||
|
if (errcode & HAL_I2C_ERRCODE_SBYTE_NORSTRT)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_SBYTE_NORSTRT");
|
||
|
if (errcode & HAL_I2C_ERRCODE_HS_NORSTRT)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_HS_NORSTRT");
|
||
|
if (errcode & HAL_I2C_ERRCODE_SBYTE_ACKDET)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_SBYTE_ACKDET");
|
||
|
if (errcode & HAL_I2C_ERRCODE_HS_ACKDET)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_HS_ACKDET");
|
||
|
if (errcode & HAL_I2C_ERRCODE_GCALL_READ)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_GCALL_READ");
|
||
|
if (errcode & HAL_I2C_ERRCODE_GCALL_NOACK)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_GCALL_NOACK");
|
||
|
if (errcode & HAL_I2C_ERRCODE_TXDATA_NOACK)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_TXDATA_NOACK");
|
||
|
if (errcode & HAL_I2C_ERRCODE_10ADDR2_NOACK)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_10ADDR2_NOACK");
|
||
|
if (errcode & HAL_I2C_ERRCODE_10ADDR1_NOACK)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_10ADDR1_NOACK");
|
||
|
if (errcode & HAL_I2C_ERRCODE_7B_ADDR_NOACK)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_7B_ADDR_NOACK");
|
||
|
|
||
|
if (errcode & HAL_I2C_ERRCODE_INV_PARAM)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_INV_PARAM");
|
||
|
if (errcode & HAL_I2C_ERRCODE_IN_USE)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_IN_USE");
|
||
|
if (errcode & HAL_I2C_ERRCODE_FIFO_ERR)
|
||
|
HAL_I2C_ERROR(0,"i2c err : HAL_I2C_ERRCODE_FIFO_ERR");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef I2C_USE_DMA
|
||
|
static void hal_i2c_tx_dma_handler(uint8_t chan, uint32_t remain_tsize, uint32_t error, struct HAL_DMA_DESC_T *lli)
|
||
|
{
|
||
|
enum HAL_I2C_ID_T id;
|
||
|
|
||
|
for (id = HAL_I2C_ID_0; id < HAL_I2C_ID_NUM; id++) {
|
||
|
if (hal_i2c_sm[id].tx_dma_cfg.ch == chan) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_rx_dma_handler(uint8_t chan, uint32_t remain_tsize, uint32_t error, struct HAL_DMA_DESC_T *lli)
|
||
|
{
|
||
|
enum HAL_I2C_ID_T id;
|
||
|
|
||
|
for (id = HAL_I2C_ID_0; id < HAL_I2C_ID_NUM; id++) {
|
||
|
if (hal_i2c_sm[id].rx_dma_cfg.ch == chan) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_dma_release(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t reg_base;
|
||
|
struct HAL_DMA_CH_CFG_T *tx_dma_cfg = NULL, *rx_dma_cfg = NULL;
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.use_dma == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
i2cip_w_tx_dma_enable(reg_base, HAL_I2C_NO);
|
||
|
i2cip_w_rx_dma_enable(reg_base, HAL_I2C_NO);
|
||
|
|
||
|
tx_dma_cfg = &hal_i2c_sm[id].tx_dma_cfg;
|
||
|
rx_dma_cfg = &hal_i2c_sm[id].rx_dma_cfg;
|
||
|
|
||
|
HAL_I2C_TRACE(1,"i2c tx free dma ch %d", tx_dma_cfg->ch);
|
||
|
if (tx_dma_cfg->ch != HAL_DMA_CHAN_NONE) {
|
||
|
hal_gpdma_cancel(tx_dma_cfg->ch);
|
||
|
hal_gpdma_free_chan(tx_dma_cfg->ch);
|
||
|
tx_dma_cfg->ch = HAL_DMA_CHAN_NONE;
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(1,"i2c rx free dma ch %d", rx_dma_cfg->ch);
|
||
|
if (rx_dma_cfg->ch != HAL_DMA_CHAN_NONE) {
|
||
|
hal_gpdma_cancel(rx_dma_cfg->ch);
|
||
|
hal_gpdma_free_chan(rx_dma_cfg->ch);
|
||
|
rx_dma_cfg->ch = HAL_DMA_CHAN_NONE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_dma_config(enum HAL_I2C_ID_T id, const struct HAL_I2C_SM_TASK_T *out_task)
|
||
|
{
|
||
|
uint32_t reg_base;
|
||
|
uint32_t i, txn;
|
||
|
uint32_t txn_start, org_start;
|
||
|
struct HAL_DMA_CH_CFG_T *tx_dma_cfg = NULL, *rx_dma_cfg = NULL;
|
||
|
enum HAL_I2C_SM_TASK_ACTION_T action;
|
||
|
uint32_t total_tx_len;
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.use_dma == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
action = out_task->action;
|
||
|
|
||
|
total_tx_len = out_task->tx_txn_len * out_task->txn_cnt;
|
||
|
if (action == HAL_I2C_SM_TASK_ACTION_M_RECV) {
|
||
|
total_tx_len += out_task->rx_txn_len * out_task->txn_cnt;
|
||
|
}
|
||
|
ASSERT(total_tx_len < ARRAY_SIZE(hal_i2c_sm[id].dma_tx_buf),
|
||
|
"%s: xfer size too large: action=%d total_tx_len=%u (should <= %u)",
|
||
|
__FUNCTION__, action, total_tx_len, ARRAY_SIZE(hal_i2c_sm[id].dma_tx_buf));
|
||
|
|
||
|
i2cip_w_tx_dma_enable(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_tx_dma_tl(reg_base, HAL_I2C_DMA_TX_TL);
|
||
|
|
||
|
tx_dma_cfg = &hal_i2c_sm[id].tx_dma_cfg;
|
||
|
memset(tx_dma_cfg, 0, sizeof(*tx_dma_cfg));
|
||
|
tx_dma_cfg->dst = 0; // useless
|
||
|
tx_dma_cfg->dst_bsize = HAL_DMA_BSIZE_1;
|
||
|
tx_dma_cfg->dst_periph = i2c_desc[id].tx_periph;
|
||
|
tx_dma_cfg->dst_width = HAL_DMA_WIDTH_HALFWORD;
|
||
|
tx_dma_cfg->handler = hal_i2c_tx_dma_handler;
|
||
|
tx_dma_cfg->src_bsize = HAL_DMA_BSIZE_1;
|
||
|
tx_dma_cfg->src_periph = 0; // useless
|
||
|
tx_dma_cfg->src_tsize = total_tx_len;
|
||
|
tx_dma_cfg->src_width = HAL_DMA_WIDTH_HALFWORD;
|
||
|
tx_dma_cfg->try_burst = 1;
|
||
|
tx_dma_cfg->type = HAL_DMA_FLOW_M2P_DMA;
|
||
|
tx_dma_cfg->src = (uint32_t)hal_i2c_sm[id].dma_tx_buf;
|
||
|
tx_dma_cfg->ch = hal_gpdma_get_chan(tx_dma_cfg->dst_periph, HAL_DMA_HIGH_PRIO);
|
||
|
HAL_I2C_TRACE(1,"i2c tx get dma ch %d", tx_dma_cfg->ch);
|
||
|
ASSERT(tx_dma_cfg->ch != HAL_DMA_CHAN_NONE, "I2C: Failed to get tx dma chan");
|
||
|
|
||
|
HAL_I2C_TRACE(3,"tx size %d cnt %d total tx size %d", out_task->tx_txn_len, out_task->txn_cnt, total_tx_len);
|
||
|
|
||
|
memset(&hal_i2c_sm[id].dma_tx_buf[0], 0, sizeof(hal_i2c_sm[id].dma_tx_buf));
|
||
|
|
||
|
for (txn = 0; txn < out_task->txn_cnt; txn++) {
|
||
|
org_start = out_task->tx_txn_len * txn;
|
||
|
txn_start = (out_task->tx_txn_len + out_task->rx_txn_len) * txn;
|
||
|
for (i = 0; i < out_task->tx_txn_len; i++) {
|
||
|
// lo byte of short : for data
|
||
|
// hi byte of short : for cmd/stop/restart
|
||
|
hal_i2c_sm[id].dma_tx_buf[txn_start + i] = out_task->tx_buf[org_start + i];
|
||
|
}
|
||
|
if (txn && out_task->restart_after_write) {
|
||
|
hal_i2c_sm[id].dma_tx_buf[txn_start] |= I2CIP_CMD_DATA_RESTART_MASK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (action == HAL_I2C_SM_TASK_ACTION_M_RECV) {
|
||
|
i2cip_w_rx_dma_enable(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_rx_dma_tl(reg_base, HAL_I2C_DMA_RX_TL);
|
||
|
|
||
|
for (txn = 0; txn < out_task->txn_cnt; txn++) {
|
||
|
txn_start = (out_task->tx_txn_len + out_task->rx_txn_len) * txn + out_task->tx_txn_len;
|
||
|
for (i = 0; i < out_task->rx_txn_len; i++) {
|
||
|
// lo byte of short : for data
|
||
|
// hi byte of short : for cmd/stop/restart
|
||
|
hal_i2c_sm[id].dma_tx_buf[txn_start + i] = I2CIP_CMD_DATA_CMD_READ_MASK;
|
||
|
}
|
||
|
if (out_task->restart_after_write) {
|
||
|
hal_i2c_sm[id].dma_tx_buf[txn_start] |= I2CIP_CMD_DATA_RESTART_MASK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(2,"rx size %d cnt %d", out_task->rx_txn_len, out_task->txn_cnt);
|
||
|
|
||
|
rx_dma_cfg = &hal_i2c_sm[id].rx_dma_cfg;
|
||
|
memset(rx_dma_cfg, 0, sizeof(*rx_dma_cfg));
|
||
|
rx_dma_cfg->dst = (uint32_t)(out_task->rx_buf);
|
||
|
rx_dma_cfg->dst_bsize = HAL_DMA_BSIZE_1;
|
||
|
rx_dma_cfg->dst_periph = 0; // useless
|
||
|
rx_dma_cfg->dst_width = HAL_DMA_WIDTH_BYTE;
|
||
|
rx_dma_cfg->handler = hal_i2c_rx_dma_handler;
|
||
|
rx_dma_cfg->src_bsize = HAL_DMA_BSIZE_1;
|
||
|
rx_dma_cfg->src_periph = i2c_desc[id].rx_periph;
|
||
|
rx_dma_cfg->src_tsize = out_task->rx_txn_len * out_task->txn_cnt;
|
||
|
rx_dma_cfg->src_width = HAL_DMA_WIDTH_BYTE;
|
||
|
rx_dma_cfg->try_burst = 0;
|
||
|
rx_dma_cfg->src = 0; // useless
|
||
|
rx_dma_cfg->type = HAL_DMA_FLOW_P2M_DMA;
|
||
|
rx_dma_cfg->ch = hal_gpdma_get_chan(rx_dma_cfg->src_periph, HAL_DMA_HIGH_PRIO);
|
||
|
HAL_I2C_TRACE(1,"i2c rx get dma ch %d", rx_dma_cfg->ch);
|
||
|
ASSERT(tx_dma_cfg->ch != HAL_DMA_CHAN_NONE, "I2C: Failed to get rx dma chan");
|
||
|
}
|
||
|
|
||
|
if (out_task->stop) {
|
||
|
hal_i2c_sm[id].dma_tx_buf[total_tx_len - 1] |= I2CIP_CMD_DATA_STOP_MASK;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef I2C_TASK_MODE
|
||
|
static void hal_i2c_sm_done_task(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
struct HAL_I2C_SM_TASK_T *task;
|
||
|
uint32_t reg_base = _i2c_get_base(id);
|
||
|
|
||
|
task = &(hal_i2c_sm[id].task[hal_i2c_sm[id].out_task]);
|
||
|
|
||
|
if (task->errcode) {
|
||
|
HAL_I2C_ERROR(1,"i2c err : 0x%X", task->errcode);
|
||
|
_i2c_show_error_code(task->errcode);
|
||
|
}
|
||
|
|
||
|
if (task->stop || task->errcode) {
|
||
|
HAL_I2C_TRACE(0,"disable i2c");
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_NO);
|
||
|
}
|
||
|
|
||
|
#ifdef I2C_USE_DMA
|
||
|
if (hal_i2c_sm[id].cfg.use_dma) {
|
||
|
hal_i2c_dma_release(id);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.use_sync) {
|
||
|
/* FIXME : os and non-os - different proc */
|
||
|
task->lock = 0;
|
||
|
} else {
|
||
|
if (task->handler) {
|
||
|
task->handler(id, task->transfer_id, task->tx_buf, task->tx_txn_len * task->txn_cnt,
|
||
|
task->rx_buf, task->rx_txn_len * task->txn_cnt, task->errcode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hal_i2c_sm[id].out_task = (hal_i2c_sm[id].out_task+1)%HAL_I2C_SM_TASK_NUM_MAX;
|
||
|
--hal_i2c_sm[id].task_count;
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_sm_next_task(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t out_task_index;
|
||
|
uint32_t reg_base, reinit;
|
||
|
enum HAL_I2C_SM_TASK_ACTION_T action;
|
||
|
struct HAL_I2C_SM_TASK_T *out_task = 0;
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
if (hal_i2c_sm[id].task_count <= 0) {
|
||
|
HAL_I2C_TRACE(0,"no task");
|
||
|
hal_i2c_sm_done(id);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
out_task_index = hal_i2c_sm[id].out_task;
|
||
|
out_task = &(hal_i2c_sm[id].task[out_task_index]);
|
||
|
action = out_task->action;
|
||
|
|
||
|
/* tx : quarter trigger TX EMPTY INT */
|
||
|
i2cip_w_tx_threshold(reg_base, HAL_I2C_TX_TL);
|
||
|
if (action == HAL_I2C_SM_TASK_ACTION_M_RECV) {
|
||
|
/* rx : three quarter trigger RX FULL INT */
|
||
|
i2cip_w_rx_threshold(reg_base, HAL_I2C_RX_TL);
|
||
|
}
|
||
|
|
||
|
#ifdef I2C_USE_DMA
|
||
|
if (hal_i2c_sm[id].cfg.use_dma) {
|
||
|
i2cip_init_int_mask(reg_base, I2CIP_INT_MASK_STOP_DET_MASK|I2CIP_INT_MASK_ERROR_MASK);
|
||
|
|
||
|
/* prepare for dma operation */
|
||
|
hal_i2c_dma_config(id, out_task);
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
/* open all interrupt */
|
||
|
i2cip_init_int_mask(reg_base, (I2CIP_INT_MASK_ALL & ~(I2CIP_INT_MASK_START_DET_MASK | I2CIP_INT_MASK_ACTIVITY_MASK)));
|
||
|
}
|
||
|
|
||
|
reinit = i2cip_r_enable_status(reg_base);
|
||
|
/* not enable : reconfig i2cip with new-task params */
|
||
|
/* enable : same operation with pre task */
|
||
|
if (!(reinit & I2CIP_ENABLE_STATUS_ENABLE_MASK)) {
|
||
|
HAL_I2C_TRACE(0,"enable i2c");
|
||
|
i2cip_w_restart(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_target_address(reg_base, out_task->target_addr);
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_YES);
|
||
|
}
|
||
|
|
||
|
#ifdef I2C_USE_DMA
|
||
|
if (hal_i2c_sm[id].cfg.use_dma) {
|
||
|
if (action == HAL_I2C_SM_TASK_ACTION_M_RECV) {
|
||
|
HAL_I2C_TRACE(0,"enable rx dma");
|
||
|
hal_gpdma_start(&hal_i2c_sm[id].rx_dma_cfg);
|
||
|
}
|
||
|
HAL_I2C_TRACE(0,"enable tx dma");
|
||
|
hal_gpdma_start(&hal_i2c_sm[id].tx_dma_cfg);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static uint32_t hal_i2c_sm_wait_task_if_need(enum HAL_I2C_ID_T id, uint32_t task_idx, uint32_t tm_ms)
|
||
|
{
|
||
|
int tmcnt;
|
||
|
struct HAL_I2C_SM_TASK_T *task = 0;
|
||
|
|
||
|
/* FIXME : task_id maybe invalid cause so-fast device operation */
|
||
|
task = &(hal_i2c_sm[id].task[task_idx]);
|
||
|
|
||
|
if (!(hal_i2c_sm[id].cfg.use_sync))
|
||
|
return 0;
|
||
|
|
||
|
/* FIXME : os and non-os - different proc */
|
||
|
tmcnt = tm_ms / HAL_I2C_DLY_MS;
|
||
|
while(1) {
|
||
|
uint32_t lock = task->lock;
|
||
|
|
||
|
if (!lock)
|
||
|
break;
|
||
|
|
||
|
if (!tmcnt) {
|
||
|
HAL_I2C_TRACE(1,"wait lock timeout %d ms", tm_ms);
|
||
|
task->errcode = HAL_I2C_ERRCODE_SYNC_TIMEOUT;
|
||
|
hal_i2c_sm_done_task(id);
|
||
|
hal_i2c_sm_next_task(id);
|
||
|
break;
|
||
|
}
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
tmcnt--;
|
||
|
}
|
||
|
return task->errcode;
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_sm_kickoff(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
if (hal_i2c_sm[id].state == HAL_I2C_SM_IDLE) {
|
||
|
hal_i2c_sm[id].state = HAL_I2C_SM_RUNNING;
|
||
|
hal_i2c_sm_next_task(id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void hal_i2c_sm_proc(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t reg_base = 0;
|
||
|
enum HAL_I2C_SM_STATE_T state;
|
||
|
enum HAL_I2C_SM_TASK_STATE_T task_state;
|
||
|
struct HAL_I2C_SM_TASK_T *task;
|
||
|
uint32_t i = 0, restart = 0, stop = 0, data = 0;
|
||
|
uint32_t ip_int_status = 0, tx_abrt_source = 0;
|
||
|
uint8_t rx_limit, tx_limit, rx_cnt, tx_cnt;
|
||
|
uint32_t total_tx_len, total_rx_len;
|
||
|
uint32_t txn_idx, txn_pos;
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
state = hal_i2c_sm[id].state;
|
||
|
task = &(hal_i2c_sm[id].task[hal_i2c_sm[id].out_task]);
|
||
|
|
||
|
ip_int_status = i2cip_r_int_status(reg_base);
|
||
|
tx_abrt_source = i2cip_r_tx_abrt_source(reg_base);
|
||
|
|
||
|
HAL_I2C_TRACE(4,"id:%d, ip_int_status=0x%X tx_abrt_source=0x%X state=%d",
|
||
|
id, ip_int_status, tx_abrt_source, state);
|
||
|
|
||
|
task_state = _i2c_chk_clr_task_error(reg_base, ip_int_status, tx_abrt_source);
|
||
|
|
||
|
if (state != HAL_I2C_SM_RUNNING) {
|
||
|
HAL_I2C_ERROR(3,"*** WARNING: No i2c task running: id=%d ip_int_status=0x%X tx_abrt_source=0x%X", id, ip_int_status, tx_abrt_source);
|
||
|
i2cip_r_clr_all_intr(reg_base);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(1,"RUNNING action=%d", task->action);
|
||
|
|
||
|
task->state |= task_state;
|
||
|
|
||
|
if (task->state & (HAL_I2C_SM_TASK_STATE_TX_ABRT | HAL_I2C_SM_TASK_STATE_FIFO_ERR)) {
|
||
|
HAL_I2C_ERROR(5,"*** ERROR:%s: id=%d task_state=0x%X ip_int_status=0x%X tx_abrt_source=0x%X", __func__, id, task->state, ip_int_status, tx_abrt_source);
|
||
|
task->errcode = tx_abrt_source;
|
||
|
if (task->state & HAL_I2C_SM_TASK_STATE_FIFO_ERR) {
|
||
|
task->errcode |= HAL_I2C_ERRCODE_FIFO_ERR;
|
||
|
}
|
||
|
/* done task on any error */
|
||
|
hal_i2c_sm_done_task(id);
|
||
|
hal_i2c_sm_next_task(id);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* stop det interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_STOP_DET_MASK) {
|
||
|
task->state |= HAL_I2C_SM_TASK_STATE_STOP;
|
||
|
i2cip_r_clr_stop_det(reg_base);
|
||
|
}
|
||
|
|
||
|
/* start det interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_START_DET_MASK) {
|
||
|
task->state |= HAL_I2C_SM_TASK_STATE_START;
|
||
|
i2cip_r_clr_start_det(reg_base);
|
||
|
}
|
||
|
|
||
|
/* activeity det interrupt */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_ACTIVITY_MASK) {
|
||
|
task->state |= HAL_I2C_SM_TASK_STATE_ACT;
|
||
|
i2cip_r_clr_activity(reg_base);
|
||
|
}
|
||
|
|
||
|
switch (task->action) {
|
||
|
case HAL_I2C_SM_TASK_ACTION_M_SEND:
|
||
|
{
|
||
|
if (hal_i2c_sm[id].cfg.use_dma == 0) {
|
||
|
/* tx empty : means tx fifo is at or below IC_TX_TL :
|
||
|
need to write more data : we can NOT clear this bit, cleared by hw */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_TX_EMPTY_MASK) {
|
||
|
total_tx_len = task->tx_txn_len * task->txn_cnt;
|
||
|
tx_limit = i2cip_r_tx_fifo_level(reg_base);
|
||
|
if (tx_limit < I2CIP_TX_FIFO_DEPTH) {
|
||
|
tx_limit = I2CIP_TX_FIFO_DEPTH - tx_limit;
|
||
|
} else {
|
||
|
tx_limit = 0;
|
||
|
}
|
||
|
HAL_I2C_TRACE(4,"m_send: tx_pos=%d tx_txn_len=%d cnt=%d tx_limit=%d",
|
||
|
task->tx_pos, task->tx_txn_len, task->txn_cnt, tx_limit);
|
||
|
for (i = task->tx_pos, tx_cnt = 0;
|
||
|
((i < total_tx_len) && (tx_cnt < tx_limit));
|
||
|
++i, ++tx_cnt) {
|
||
|
/* last byte : we need to decide stop */
|
||
|
if (i == total_tx_len - 1) {
|
||
|
stop = task->stop ? I2CIP_CMD_DATA_STOP_MASK : 0;
|
||
|
} else {
|
||
|
stop = 0;
|
||
|
}
|
||
|
if (task->txn_cnt == 1) {
|
||
|
txn_pos = i;
|
||
|
} else {
|
||
|
txn_pos = i % task->tx_txn_len;
|
||
|
}
|
||
|
/* first byte : need to decide restart */
|
||
|
if (i && task->restart_after_write && txn_pos == 0) {
|
||
|
restart = I2CIP_CMD_DATA_RESTART_MASK;
|
||
|
} else {
|
||
|
restart = 0;
|
||
|
}
|
||
|
/* write data to FIFO */
|
||
|
i2cip_w_cmd_data(reg_base,
|
||
|
task->tx_buf[i] | I2CIP_CMD_DATA_CMD_WRITE_MASK | restart | stop);
|
||
|
|
||
|
HAL_I2C_TRACE(3,"m_send: data=0x%02X restart=0x%X stop=0x%X",
|
||
|
task->tx_buf[i], restart, stop);
|
||
|
}
|
||
|
|
||
|
task->tx_pos = i;
|
||
|
|
||
|
/* all write action done : do NOT need tx empty int */
|
||
|
if (task->tx_pos == total_tx_len) {
|
||
|
i2cip_clear_int_mask(reg_base, I2CIP_INT_MASK_TX_EMPTY_MASK);
|
||
|
}
|
||
|
HAL_I2C_TRACE(1,"m_send: i2c status=0x%X", i2cip_r_status(reg_base));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* stop condition : done task */
|
||
|
if (task->state & HAL_I2C_SM_TASK_STATE_STOP) {
|
||
|
HAL_I2C_TRACE(1,"m_send: task->state:0x%X", task->state);
|
||
|
hal_i2c_sm_done_task(id);
|
||
|
hal_i2c_sm_next_task(id);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case HAL_I2C_SM_TASK_ACTION_M_RECV:
|
||
|
{
|
||
|
if (hal_i2c_sm[id].cfg.use_dma == 0) {
|
||
|
/* rx full : need to read */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_RX_FULL_MASK) {
|
||
|
total_rx_len = task->rx_txn_len * task->txn_cnt;
|
||
|
rx_limit = i2cip_r_rx_fifo_level(reg_base);
|
||
|
HAL_I2C_TRACE(4,"m_recv:full: rx_pos=%d rx_txn_len=%d cnt=%d rx_limit=%d",
|
||
|
task->rx_pos, task->rx_txn_len, task->txn_cnt, rx_limit);
|
||
|
for (i = task->rx_pos, rx_cnt = 0;
|
||
|
((i < total_rx_len) && (rx_cnt < rx_limit));
|
||
|
++i, ++rx_cnt) {
|
||
|
task->rx_buf[i] = i2cip_r_cmd_data(reg_base);
|
||
|
HAL_I2C_TRACE(2,"m_recv:full: rx_buf[%d] 0x%X", i, task->rx_buf[i]);
|
||
|
}
|
||
|
task->rx_pos = i;
|
||
|
}
|
||
|
|
||
|
/* tx empty : means tx fifo is at or below IC_TX_TL :
|
||
|
need to write more data : we can NOT clear this bit, cleared by hw */
|
||
|
if (ip_int_status & I2CIP_INT_STATUS_TX_EMPTY_MASK) {
|
||
|
total_tx_len = (task->tx_txn_len + task->rx_txn_len) * task->txn_cnt;
|
||
|
tx_limit = i2cip_r_tx_fifo_level(reg_base);
|
||
|
if (tx_limit < I2CIP_TX_FIFO_DEPTH) {
|
||
|
tx_limit = I2CIP_TX_FIFO_DEPTH - tx_limit;
|
||
|
} else {
|
||
|
tx_limit = 0;
|
||
|
}
|
||
|
rx_limit = task->rx_cmd_sent - task->rx_pos + 1;
|
||
|
if (rx_limit < I2CIP_RX_FIFO_DEPTH) {
|
||
|
rx_limit = I2CIP_RX_FIFO_DEPTH - rx_limit;
|
||
|
} else {
|
||
|
rx_limit = 0;
|
||
|
}
|
||
|
HAL_I2C_TRACE(6,"m_recv:txEmpty: tx_pos=%d tx_txn_len=%d rx_txn_len=%d cnt=%d tx_limit=%d rx_limit=%d",
|
||
|
task->tx_pos, task->tx_txn_len, task->rx_txn_len, task->txn_cnt, tx_limit, rx_limit);
|
||
|
if (tx_limit > rx_limit) {
|
||
|
tx_limit = rx_limit;
|
||
|
}
|
||
|
for (i = task->tx_pos, tx_cnt = 0;
|
||
|
((i < total_tx_len) && (tx_cnt < tx_limit));
|
||
|
++i, ++tx_cnt) {
|
||
|
/* last byte : we need to decide stop */
|
||
|
if (i == (total_tx_len - 1)) {
|
||
|
stop = task->stop ? I2CIP_CMD_DATA_STOP_MASK : 0;
|
||
|
} else {
|
||
|
stop = 0;
|
||
|
}
|
||
|
if (task->txn_cnt == 1) {
|
||
|
txn_idx = 0;
|
||
|
txn_pos = i;
|
||
|
} else {
|
||
|
txn_idx = i / (task->tx_txn_len + task->rx_txn_len);
|
||
|
txn_pos = i % (task->tx_txn_len + task->rx_txn_len);
|
||
|
}
|
||
|
/* first byte : need to decide restart */
|
||
|
if (i && task->restart_after_write && (txn_pos == 0 || txn_pos == task->tx_txn_len)) {
|
||
|
restart = I2CIP_CMD_DATA_RESTART_MASK;
|
||
|
} else {
|
||
|
restart = 0;
|
||
|
}
|
||
|
/* real write data */
|
||
|
if (txn_pos < task->tx_txn_len) {
|
||
|
if (task->txn_cnt == 1) {
|
||
|
data = task->tx_buf[txn_pos];
|
||
|
} else {
|
||
|
data = task->tx_buf[txn_idx * task->tx_txn_len + txn_pos];
|
||
|
}
|
||
|
} else {
|
||
|
data = I2CIP_CMD_DATA_CMD_READ_MASK;
|
||
|
task->rx_cmd_sent++;
|
||
|
}
|
||
|
|
||
|
i2cip_w_cmd_data(reg_base, data | restart | stop);
|
||
|
HAL_I2C_TRACE(4,"m_recv:tx: data[%u]=0x%02X restart=0x%X stop=0x%X",
|
||
|
i, data, restart, stop);
|
||
|
}
|
||
|
|
||
|
task->tx_pos = i;
|
||
|
|
||
|
/* all write action done */
|
||
|
if (task->tx_pos == total_tx_len) {
|
||
|
i2cip_clear_int_mask(reg_base, I2CIP_INT_MASK_TX_EMPTY_MASK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* stop condition : need to read out all rx fifo */
|
||
|
if (task->state & HAL_I2C_SM_TASK_STATE_STOP) {
|
||
|
if (hal_i2c_sm[id].cfg.use_dma) {
|
||
|
#ifdef I2C_USE_DMA
|
||
|
if (hal_i2c_sm[id].rx_dma_cfg.ch == HAL_DMA_CHAN_NONE) {
|
||
|
HAL_I2C_TRACE(0,"m_recv:stop:WARNING: bad rx dma chan!");
|
||
|
} else {
|
||
|
if (hal_dma_chan_busy(hal_i2c_sm[id].rx_dma_cfg.ch)) {
|
||
|
HAL_I2C_TRACE(0,"m_recv:stop:WARNING: rx dma not finished yet!");
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
} else {
|
||
|
rx_limit = i2cip_r_rx_fifo_level(reg_base);
|
||
|
HAL_I2C_TRACE(1,"m_recv:stop: rx_limit=%d", rx_limit);
|
||
|
for (i = task->rx_pos, rx_cnt = 0;
|
||
|
((rx_cnt < rx_limit) && (i < task->rx_txn_len));
|
||
|
++i, ++rx_cnt) {
|
||
|
task->rx_buf[i] = i2cip_r_cmd_data(reg_base);
|
||
|
HAL_I2C_TRACE(2,"m_recv:stop: rx_buf[%d] 0x%X", i, task->rx_buf[i]);
|
||
|
}
|
||
|
task->rx_pos = i;
|
||
|
if (task->rx_pos != task->rx_txn_len * task->txn_cnt) {
|
||
|
HAL_I2C_TRACE(3,"m_recv:stop:WARNING: rx_pos(%u) != rx_txn_len(%u) * txn_cnt(%u)", task->rx_pos, task->rx_txn_len, task->txn_cnt);
|
||
|
}
|
||
|
}
|
||
|
hal_i2c_sm_done_task(id);
|
||
|
hal_i2c_sm_next_task(id);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hal_i2c_irq_handler(void)
|
||
|
{
|
||
|
enum HAL_I2C_ID_T id;
|
||
|
|
||
|
for (id = HAL_I2C_ID_0; id < HAL_I2C_ID_NUM; id++) {
|
||
|
if (NVIC_GetActive(i2c_desc[id].irq)) {
|
||
|
hal_i2c_sm_proc(id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef I2C_SIMPLE_MODE
|
||
|
void hal_i2c_irq_handler_s(void)
|
||
|
{
|
||
|
enum HAL_I2C_ID_T id;
|
||
|
|
||
|
for (id = HAL_I2C_ID_0; id < HAL_I2C_ID_NUM; id++) {
|
||
|
if (NVIC_GetActive(i2c_desc[id].irq)) {
|
||
|
hal_i2c_simple_proc(id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef I2C_SENSOR_ENGINE
|
||
|
void hal_i2c_irq_handler_sensor_eng(void)
|
||
|
{
|
||
|
enum HAL_I2C_ID_T id;
|
||
|
|
||
|
for (id = HAL_I2C_ID_0; id < HAL_I2C_ID_NUM; id++) {
|
||
|
if (NVIC_GetActive(i2c_desc[id].irq)) {
|
||
|
hal_i2c_sensor_eng_proc(id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static int POSSIBLY_UNUSED hal_i2c_nvic_setup_irq(enum HAL_I2C_ID_T id, uint32_t handler)
|
||
|
{
|
||
|
IRQn_Type irqt = i2c_desc[id].irq;
|
||
|
|
||
|
NVIC_SetVector(irqt, handler);
|
||
|
NVIC_SetPriority(irqt, IRQ_PRIORITY_NORMAL);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int hal_i2c_nvic_enable_irq(enum HAL_I2C_ID_T id, int enabled)
|
||
|
{
|
||
|
IRQn_Type irqt = i2c_desc[id].irq;
|
||
|
|
||
|
if (enabled) {
|
||
|
NVIC_ClearPendingIRQ(irqt);
|
||
|
NVIC_EnableIRQ(irqt);
|
||
|
} else {
|
||
|
NVIC_DisableIRQ(irqt);
|
||
|
NVIC_ClearPendingIRQ(irqt);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_open(enum HAL_I2C_ID_T id, const struct HAL_I2C_CONFIG_T *cfg)
|
||
|
{
|
||
|
uint32_t reg_base;
|
||
|
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].state != HAL_I2C_SM_CLOSED) {
|
||
|
return HAL_I2C_ERRCODE_IN_USE;
|
||
|
}
|
||
|
|
||
|
hal_i2c_sm_init(id, cfg);
|
||
|
|
||
|
hal_cmu_clock_enable(i2c_desc[id].mod);
|
||
|
hal_cmu_clock_enable(i2c_desc[id].apb);
|
||
|
hal_cmu_reset_clear(i2c_desc[id].mod);
|
||
|
hal_cmu_reset_clear(i2c_desc[id].apb);
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
HAL_I2C_TRACE(2,"i2c id=%d reg_base=0x%X", id, reg_base);
|
||
|
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_NO);
|
||
|
|
||
|
i2cip_w_target_address(reg_base, 0x18);
|
||
|
|
||
|
/* clear */
|
||
|
i2cip_w_clear_ctrl(reg_base);
|
||
|
|
||
|
/* as master */
|
||
|
if (cfg->as_master) {
|
||
|
i2cip_w_disable_slave(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_master_mode(reg_base, HAL_I2C_YES);
|
||
|
} else {
|
||
|
i2cip_w_disable_slave(reg_base, HAL_I2C_NO);
|
||
|
i2cip_w_master_mode(reg_base, HAL_I2C_NO);
|
||
|
|
||
|
/* address as slave */
|
||
|
i2cip_w_address_as_slave(reg_base, cfg->addr_as_slave);
|
||
|
}
|
||
|
|
||
|
/* speed */
|
||
|
_i2c_set_bus_speed(id, cfg->speed);
|
||
|
if (0) {
|
||
|
#ifdef I2C_SIMPLE_MODE
|
||
|
} else if (cfg->mode == HAL_I2C_API_MODE_SIMPLE) {
|
||
|
HAL_I2C_TRACE(0,"simple mode");
|
||
|
hal_i2c_nvic_setup_irq(id, (uint32_t)hal_i2c_irq_handler_s);
|
||
|
|
||
|
/* only open slave related int, polling in master */
|
||
|
/* read req (master read us), rx full (master write us) */
|
||
|
if (cfg->as_master) {
|
||
|
i2cip_init_int_mask(reg_base, I2CIP_INT_UNMASK_ALL);
|
||
|
} else {
|
||
|
i2cip_init_int_mask(reg_base, I2CIP_INT_MASK_RD_REQ_MASK|I2CIP_INT_MASK_RX_FULL_MASK);
|
||
|
}
|
||
|
|
||
|
/* rx threshold, 1 byte trigger RX_FULL */
|
||
|
i2cip_w_rx_threshold(reg_base, I2CIP_RX_TL_1_BYTE);
|
||
|
|
||
|
/* tx threshold, 1 byte trigger TX_EMPTY */
|
||
|
i2cip_w_tx_threshold(reg_base, I2CIP_TX_TL_1_BYTE);
|
||
|
|
||
|
/* enable restart */
|
||
|
i2cip_w_restart(reg_base, HAL_I2C_YES);
|
||
|
|
||
|
/* enable i2c */
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_YES);
|
||
|
#endif
|
||
|
#ifdef I2C_TASK_MODE
|
||
|
} else if (cfg->mode == HAL_I2C_API_MODE_TASK) {
|
||
|
/* only use task irq handler when master mode */
|
||
|
HAL_I2C_TRACE(0,"task mode");
|
||
|
if (!cfg->as_master) {
|
||
|
HAL_I2C_TRACE(0,"not as master");
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
#ifndef I2C_USE_DMA
|
||
|
if (cfg->use_dma) {
|
||
|
HAL_I2C_TRACE(0,"using DMA when I2C_USE_DMA is NOT enabled");
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
hal_i2c_nvic_setup_irq(id, (uint32_t)hal_i2c_irq_handler);
|
||
|
#endif
|
||
|
#ifdef I2C_SENSOR_ENGINE
|
||
|
} else if (cfg->mode == HAL_I2C_API_MODE_SENSOR_ENGINE) {
|
||
|
HAL_I2C_TRACE(0,"sensor engine mode");
|
||
|
ASSERT(cfg->as_master, "%s: i2c master should be used with sensor engine", __FUNCTION__);
|
||
|
ASSERT(cfg->use_dma, "%s: i2c dma should be used with sensor engine", __FUNCTION__);
|
||
|
|
||
|
hal_i2c_nvic_setup_irq(id, (uint32_t)hal_i2c_irq_handler_sensor_eng);
|
||
|
#endif
|
||
|
} else {
|
||
|
ASSERT(false, "%s: Bad i2c api mode: %u", __FUNCTION__, cfg->mode);
|
||
|
}
|
||
|
|
||
|
hal_i2c_nvic_enable_irq(id, HAL_I2C_YES);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_close(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t reg_base;
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].state == HAL_I2C_SM_CLOSED) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
hal_i2c_nvic_enable_irq(id, HAL_I2C_NO);
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_NO);
|
||
|
|
||
|
#if defined(I2C_TASK_MODE) || defined(I2C_SENSOR_ENGINE)
|
||
|
#ifdef I2C_USE_DMA
|
||
|
hal_i2c_dma_release(id);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
hal_cmu_reset_set(i2c_desc[id].apb);
|
||
|
hal_cmu_reset_set(i2c_desc[id].mod);
|
||
|
hal_cmu_clock_disable(i2c_desc[id].apb);
|
||
|
hal_cmu_clock_disable(i2c_desc[id].mod);
|
||
|
|
||
|
hal_i2c_sm[id].state = HAL_I2C_SM_CLOSED;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* task mode */
|
||
|
#ifdef I2C_TASK_MODE
|
||
|
uint32_t hal_i2c_task_msend(enum HAL_I2C_ID_T id, uint16_t device_addr,
|
||
|
const uint8_t *tx_buf, uint16_t tx_item_len,
|
||
|
uint16_t item_cnt, uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
uint32_t task_idx;
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.mode != HAL_I2C_API_MODE_TASK) {
|
||
|
HAL_I2C_TRACE(0,"send: not task mode");
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
|
||
|
task_idx = hal_i2c_sm_commit(id, tx_buf, tx_item_len, NULL, 0, item_cnt,
|
||
|
device_addr, HAL_I2C_SM_TASK_ACTION_M_SEND,
|
||
|
transfer_id, handler);
|
||
|
|
||
|
hal_i2c_sm_kickoff(id);
|
||
|
return hal_i2c_sm_wait_task_if_need(id, task_idx, HAL_I2C_SYNC_TM_MS);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_task_send(enum HAL_I2C_ID_T id, uint16_t device_addr, const uint8_t *tx_buf, uint16_t tx_len,
|
||
|
uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
return hal_i2c_task_msend(id, device_addr, tx_buf, tx_len, 1, transfer_id, handler);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_task_mrecv(enum HAL_I2C_ID_T id, uint16_t device_addr, const uint8_t *tx_buf, uint16_t tx_item_len,
|
||
|
uint8_t *rx_buf, uint16_t rx_item_len, uint16_t item_cnt,
|
||
|
uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
uint32_t task_idx;
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.mode != HAL_I2C_API_MODE_TASK) {
|
||
|
HAL_I2C_TRACE(0,"recv: not task mode");
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
|
||
|
task_idx = hal_i2c_sm_commit(id, tx_buf, tx_item_len, rx_buf, rx_item_len, item_cnt,
|
||
|
device_addr, HAL_I2C_SM_TASK_ACTION_M_RECV,
|
||
|
transfer_id, handler);
|
||
|
|
||
|
hal_i2c_sm_kickoff(id);
|
||
|
return hal_i2c_sm_wait_task_if_need(id, task_idx, HAL_I2C_SYNC_TM_MS);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_task_recv(enum HAL_I2C_ID_T id, uint16_t device_addr, const uint8_t *tx_buf, uint16_t tx_len,
|
||
|
uint8_t *rx_buf, uint16_t rx_len,
|
||
|
uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
return hal_i2c_task_mrecv(id, device_addr, tx_buf, tx_len, rx_buf, rx_len, 1, transfer_id, handler);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_send(enum HAL_I2C_ID_T id, uint32_t device_addr, uint8_t *buf, uint32_t reg_len, uint32_t value_len,
|
||
|
uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
return hal_i2c_task_send(id, device_addr, buf, reg_len + value_len, transfer_id, handler);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_recv(enum HAL_I2C_ID_T id, uint32_t device_addr, uint8_t *buf, uint32_t reg_len, uint32_t value_len,
|
||
|
uint8_t restart_after_write, uint32_t transfer_id, HAL_I2C_TRANSFER_HANDLER_T handler)
|
||
|
{
|
||
|
return hal_i2c_task_recv(id, device_addr, buf, reg_len, buf + reg_len, value_len, transfer_id, handler);
|
||
|
}
|
||
|
#endif
|
||
|
/* task mode end */
|
||
|
|
||
|
/* simple mode */
|
||
|
#ifdef I2C_SIMPLE_MODE
|
||
|
static void hal_i2c_simple_proc(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t reg_base = _i2c_get_base(id);
|
||
|
uint32_t irq_status = i2cip_r_raw_int_status(reg_base);
|
||
|
uint32_t abt_source = i2cip_r_tx_abrt_source(reg_base);
|
||
|
HAL_I2C_INT_HANDLER_T h = hal_i2c_int_handlers[id];
|
||
|
|
||
|
i2cip_r_clr_all_intr(reg_base);
|
||
|
|
||
|
if (h) {
|
||
|
HAL_I2C_TRACE(3,"%s:irq=0x%X abt=0x%X", __func__, irq_status, abt_source);
|
||
|
h(id, irq_status, abt_source);
|
||
|
}
|
||
|
|
||
|
// TODO: clean irq after callback done ?
|
||
|
i2cip_r_clr_all_intr(reg_base);
|
||
|
|
||
|
HAL_I2C_TRACE(3,"%s:0x%X 0x%X", __func__,
|
||
|
i2cip_r_status(reg_base), i2cip_r_raw_int_status(reg_base));
|
||
|
}
|
||
|
|
||
|
static uint32_t _i2c_check_tx_abrt_error(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t reg_base = _i2c_get_base(id);
|
||
|
|
||
|
if (i2cip_r_raw_int_status(reg_base) & I2CIP_RAW_INT_STATUS_TX_ABRT_MASK)
|
||
|
return i2cip_r_tx_abrt_source(reg_base);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_slv_write(enum HAL_I2C_ID_T id, uint8_t *buf, uint32_t len, uint32_t *act_write)
|
||
|
{
|
||
|
uint32_t reg_base = 0, i = 0, ret = 0;
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
*act_write = 0;
|
||
|
|
||
|
for (i = 0; i < len;) {
|
||
|
/* Tx Fifo Not Full */
|
||
|
if (i2cip_r_status(reg_base) & I2CIP_STATUS_TFNF_MASK) {
|
||
|
i2cip_w_cmd_data(reg_base, buf[i]);
|
||
|
++(*act_write);
|
||
|
++i;
|
||
|
}
|
||
|
else {
|
||
|
/* wait for TFNF & not rx done & no error */
|
||
|
while(!(i2cip_r_status(reg_base) & I2CIP_STATUS_TFNF_MASK)
|
||
|
&& !(i2cip_r_raw_int_status(reg_base) & I2CIP_RAW_INT_STATUS_RX_DONE_MASK)
|
||
|
&& !(ret = _i2c_check_tx_abrt_error(reg_base)));
|
||
|
|
||
|
if (ret || (i2cip_r_raw_int_status(reg_base) & I2CIP_RAW_INT_STATUS_RX_DONE_MASK))
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* FIXME : tx empty is not end of transmit, i2cip may transmit the last byte */
|
||
|
while(!(i2cip_r_status(reg_base) & I2CIP_STATUS_TFE_SHIFT)
|
||
|
&& !(ret = _i2c_check_tx_abrt_error(reg_base)));
|
||
|
|
||
|
/* wait to idle */
|
||
|
/* FIXME : time out */
|
||
|
while(i2cip_r_status(reg_base) & I2CIP_STATUS_ACT_MASK);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_slv_read(enum HAL_I2C_ID_T id, uint8_t *buf, uint32_t len, uint32_t *act_read)
|
||
|
{
|
||
|
uint32_t reg_base = 0, i = 0, ret = 0, depth = 0;
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
*act_read = 0;
|
||
|
/* slave mode : just read */
|
||
|
for (i = 0; i < len;) {
|
||
|
/* Rx Fifo Not Empty */
|
||
|
if (i2cip_r_status(reg_base) & I2CIP_STATUS_RFNE_MASK) {
|
||
|
buf[i] = i2cip_r_cmd_data(reg_base);
|
||
|
++(*act_read);
|
||
|
++i;
|
||
|
}
|
||
|
else {
|
||
|
/* wait for RFNE & no stop & no error */
|
||
|
while(!(i2cip_r_status(reg_base) & I2CIP_STATUS_RFNE_MASK)
|
||
|
&& !(i2cip_r_raw_int_status(reg_base) & I2CIP_RAW_INT_STATUS_STOP_DET_MASK)
|
||
|
&& !(ret = _i2c_check_tx_abrt_error(reg_base))) {
|
||
|
}
|
||
|
|
||
|
if (ret || (i2cip_r_raw_int_status(reg_base) & I2CIP_RAW_INT_STATUS_STOP_DET_MASK)) {
|
||
|
HAL_I2C_TRACE(2,"drv:i2c slave read ret 0x%X, raw status 0x%X", ret, i2cip_r_raw_int_status(reg_base));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* may left some bytes in rx fifo */
|
||
|
depth = i2cip_r_rx_fifo_level(reg_base);
|
||
|
HAL_I2C_TRACE(1,"drv:i2c slave read depth %d", depth);
|
||
|
while (depth > 0 && i < len) {
|
||
|
buf[i] = i2cip_r_cmd_data(reg_base);
|
||
|
++(*act_read);
|
||
|
++i;
|
||
|
--depth;
|
||
|
}
|
||
|
|
||
|
/* wait to idle */
|
||
|
while(i2cip_r_status(reg_base) & I2CIP_STATUS_ACT_MASK);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void i2c_clear_special_tx_abrt(uint32_t reg_base)
|
||
|
{
|
||
|
uint32_t abrt = i2cip_r_tx_abrt_source(reg_base);
|
||
|
|
||
|
i2cip_r_clr_tx_abrt(reg_base);
|
||
|
|
||
|
if (abrt & I2CIP_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT_MASK) {
|
||
|
i2cip_w_restart(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_special_bit(reg_base, HAL_I2C_NO);
|
||
|
i2cip_w_gc_or_start_bit(reg_base, HAL_I2C_NO);
|
||
|
i2cip_r_clr_tx_abrt(reg_base);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static uint32_t _i2c_check_raw_int_status(uint32_t reg_base, uint32_t mask)
|
||
|
{
|
||
|
uint32_t regval = i2cip_r_raw_int_status(reg_base);
|
||
|
|
||
|
HAL_I2C_TRACE(3,"%s: raw status=0x%X mask=0x%X", __func__, regval, mask);
|
||
|
return regval & mask;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_mst_write(enum HAL_I2C_ID_T id, uint32_t dev_addr,
|
||
|
const uint8_t *buf, uint32_t len, uint32_t *act_write,
|
||
|
uint32_t restart, uint32_t stop, uint32_t yield)
|
||
|
{
|
||
|
uint32_t i, tar, wrcnt, ret = 0;
|
||
|
uint32_t reg_base;
|
||
|
uint32_t start_time, timeout;
|
||
|
uint32_t res, sto;
|
||
|
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.mode != HAL_I2C_API_MODE_SIMPLE) {
|
||
|
HAL_I2C_TRACE(0,"mst_write: not simple mode");
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(7,"%s:id=%d addr=0x%02X buf=0x%X len=%d res=%d sto=%d",
|
||
|
__func__, id, dev_addr, (int)buf, len, restart, stop);
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
//update TAR
|
||
|
tar = i2cip_r_target_address_reg(reg_base);
|
||
|
if (tar != dev_addr) {
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_ACT_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
while((i2cip_r_status(reg_base) & I2CIP_STATUS_ACT_MASK)) {
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
HAL_I2C_TRACE(1,"%s:wait bus idle timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_ACT_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_NO);
|
||
|
i2cip_w_target_address(reg_base, dev_addr);
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_YES);
|
||
|
HAL_I2C_TRACE(3,"%s:update tar to 0x%02X from 0x%02X", __func__, dev_addr, tar);
|
||
|
}
|
||
|
|
||
|
// check error
|
||
|
if (_i2c_check_raw_int_status(reg_base, I2CIP_RAW_INT_STATUS_TX_ABRT_MASK
|
||
|
| I2CIP_RAW_INT_STATUS_TX_OVER_MASK
|
||
|
| I2CIP_RAW_INT_STATUS_RX_OVER_MASK
|
||
|
| I2CIP_RAW_INT_STATUS_RX_UNDER_MASK)) {
|
||
|
i2cip_r_clr_all_intr(reg_base);
|
||
|
i2c_clear_special_tx_abrt(reg_base);
|
||
|
HAL_I2C_TRACE(1,"clear error status done before xfer: status=0x%X",
|
||
|
i2cip_r_raw_int_status(reg_base));
|
||
|
}
|
||
|
|
||
|
// start to transmit
|
||
|
wrcnt = 0;
|
||
|
for (i = 0; i < len; i++) {
|
||
|
if (i == 0) {
|
||
|
res = restart ? I2CIP_CMD_DATA_RESTART_MASK : 0;
|
||
|
} else {
|
||
|
res = 0;
|
||
|
}
|
||
|
if (i == (len - 1)) {
|
||
|
sto = stop ? I2CIP_CMD_DATA_STOP_MASK : 0;
|
||
|
} else {
|
||
|
sto = 0;
|
||
|
}
|
||
|
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_TFNF_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
while (!(i2cip_r_status(reg_base) & I2CIP_STATUS_TFNF_MASK)) {
|
||
|
ret = _i2c_check_raw_int_status(reg_base, I2CIP_RAW_INT_STATUS_TX_ABRT_MASK);
|
||
|
if (ret) {
|
||
|
i2c_clear_special_tx_abrt(reg_base);
|
||
|
HAL_I2C_TRACE(2,"%s:error 0x%X", __func__, ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
HAL_I2C_TRACE(1,"%s:wait tfnf timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_TFNF_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
i2cip_w_cmd_data(reg_base, buf[i] | res | sto
|
||
|
| I2CIP_CMD_DATA_CMD_WRITE_MASK);
|
||
|
|
||
|
HAL_I2C_TRACE(4,"send write cmd: data[%d]=0x%02X res=0x%X sto=0x%X", i, buf[i], res, sto);
|
||
|
wrcnt++;
|
||
|
}
|
||
|
|
||
|
if (act_write)
|
||
|
*act_write = wrcnt;
|
||
|
|
||
|
if (stop) {
|
||
|
// wait bus idle
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_ACT_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
while (i2cip_r_status(reg_base) & I2CIP_STATUS_ACT_MASK) {
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
if (_i2c_check_raw_int_status(reg_base, I2CIP_RAW_INT_STATUS_TX_ABRT_MASK)) {
|
||
|
i2cip_r_clr_all_intr(reg_base);
|
||
|
i2c_clear_special_tx_abrt(reg_base);
|
||
|
HAL_I2C_TRACE(0,"clear error status done after xfer");
|
||
|
}
|
||
|
HAL_I2C_TRACE(1,"%s:wait act timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_ACT_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// wait until txfifo empty
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_TFE_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
while(!(i2cip_r_status(reg_base) & I2CIP_STATUS_TFE_MASK)) {
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
HAL_I2C_TRACE(1,"%s:wait tfe timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_TFE_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(1,"%s:done", __func__);
|
||
|
return 0;
|
||
|
exit:
|
||
|
HAL_I2C_TRACE(3,"%s:error=0x%X, status=0x%X", __func__, ret,
|
||
|
i2cip_r_raw_int_status(reg_base));
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_mst_read(enum HAL_I2C_ID_T id, uint32_t dev_addr,
|
||
|
uint8_t *buf, uint32_t len, uint32_t *act_read,
|
||
|
uint32_t restart, uint32_t stop, uint32_t yield)
|
||
|
{
|
||
|
uint32_t i, j, tar, rdcnt, wrcnt, ret = 0;
|
||
|
uint32_t reg_base;
|
||
|
uint32_t start_time, timeout;
|
||
|
uint32_t res, sto;
|
||
|
uint8_t tmp;
|
||
|
uint8_t rx_ongoing, tx_limit;
|
||
|
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.mode != HAL_I2C_API_MODE_SIMPLE) {
|
||
|
HAL_I2C_TRACE(0,"mst_read: not simple mode");
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(7,"%s:id=%d addr=0x%02X buf=0x%X len=%d res=%d sto=%d",
|
||
|
__func__, id, dev_addr, (int)buf, len, restart, stop);
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
// update TAR
|
||
|
tar = i2cip_r_target_address_reg(reg_base);
|
||
|
if (tar != dev_addr) {
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_ACT_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
while((i2cip_r_status(reg_base) & I2CIP_STATUS_ACT_MASK)) {
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
HAL_I2C_TRACE(1,"%s:wait bus idle timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_ACT_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_NO);
|
||
|
i2cip_w_target_address(reg_base, dev_addr);
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_YES);
|
||
|
HAL_I2C_TRACE(3,"%s:update tar to 0x%02X from 0x%02X", __func__, dev_addr, tar);
|
||
|
}
|
||
|
|
||
|
// clear fifo by reading
|
||
|
j = i2cip_r_rx_fifo_level(reg_base);
|
||
|
if (j) {
|
||
|
for (i = 0;i < j; i++) {
|
||
|
tmp = i2cip_r_cmd_data(reg_base);
|
||
|
HAL_I2C_TRACE(2,"%s:discard data 0x%02X", __func__, tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check error
|
||
|
if (_i2c_check_raw_int_status(reg_base, I2CIP_RAW_INT_STATUS_TX_ABRT_MASK
|
||
|
| I2CIP_RAW_INT_STATUS_TX_OVER_MASK
|
||
|
| I2CIP_RAW_INT_STATUS_RX_OVER_MASK
|
||
|
| I2CIP_RAW_INT_STATUS_RX_UNDER_MASK)) {
|
||
|
i2cip_r_clr_all_intr(reg_base);
|
||
|
i2c_clear_special_tx_abrt(reg_base);
|
||
|
HAL_I2C_TRACE(1,"clear error status done before xfer, status=0x%X",
|
||
|
i2cip_r_raw_int_status(reg_base));
|
||
|
}
|
||
|
|
||
|
// read data
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_RFNE_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
wrcnt = 0;
|
||
|
rdcnt = 0;
|
||
|
while(rdcnt < len) {
|
||
|
// send reading cmd
|
||
|
rx_ongoing = i2cip_r_tx_fifo_level(reg_base) + i2cip_r_rx_fifo_level(reg_base) + 1;
|
||
|
if (rx_ongoing < I2CIP_RX_FIFO_DEPTH) {
|
||
|
tx_limit = I2CIP_RX_FIFO_DEPTH - rx_ongoing;
|
||
|
} else {
|
||
|
tx_limit = 0;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < tx_limit && wrcnt < len; i++, wrcnt++) {
|
||
|
if (!(i2cip_r_status(reg_base) & I2CIP_STATUS_TFNF_MASK)) {
|
||
|
break;
|
||
|
}
|
||
|
if (wrcnt == 0) {
|
||
|
res = restart ? I2CIP_CMD_DATA_RESTART_MASK : 0;
|
||
|
} else {
|
||
|
res = 0;
|
||
|
}
|
||
|
if (wrcnt == len - 1) {
|
||
|
sto = stop ? I2CIP_CMD_DATA_STOP_MASK : 0;
|
||
|
} else {
|
||
|
sto = 0;
|
||
|
}
|
||
|
|
||
|
i2cip_w_cmd_data(reg_base, I2CIP_CMD_DATA_CMD_READ_MASK | res | sto);
|
||
|
HAL_I2C_TRACE(3,"send read cmd: [%u] res=0x%X, sto=0x%X", wrcnt, res, sto);
|
||
|
}
|
||
|
|
||
|
if (i2cip_r_status(reg_base) & I2CIP_STATUS_RFNE_MASK) {
|
||
|
tmp = i2cip_r_cmd_data(reg_base);
|
||
|
HAL_I2C_TRACE(2,"i2c recv [%u] 0x%02X", rdcnt, tmp);
|
||
|
if (buf) {
|
||
|
buf[rdcnt++] = tmp;
|
||
|
}
|
||
|
start_time = hal_sys_timer_get();
|
||
|
} else {
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
HAL_I2C_TRACE(1,"%s:wait rfne timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_RFNE_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (act_read) *act_read = rdcnt;
|
||
|
|
||
|
if (stop) {
|
||
|
timeout = MS_TO_TICKS(HAL_I2C_WAIT_ACT_MS);
|
||
|
start_time = hal_sys_timer_get();
|
||
|
while (i2cip_r_status(reg_base) & I2CIP_STATUS_ACT_MASK){
|
||
|
if (hal_sys_timer_get() - start_time >= timeout) {
|
||
|
HAL_I2C_TRACE(1,"%s:wait act timeout", __func__);
|
||
|
ret = HAL_I2C_ERRCODE_ACT_TIMEOUT;
|
||
|
goto exit;
|
||
|
}
|
||
|
if (yield) {
|
||
|
hal_i2c_delay_ms(HAL_I2C_DLY_MS);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HAL_I2C_TRACE(1,"%s:done", __func__);
|
||
|
return 0;
|
||
|
exit:
|
||
|
HAL_I2C_TRACE(3,"%s:error=0x%X, status=0x%X", __func__, ret,
|
||
|
i2cip_r_raw_int_status(reg_base));
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_simple_send(enum HAL_I2C_ID_T id, uint16_t device_addr, const uint8_t *tx_buf, uint16_t tx_len)
|
||
|
{
|
||
|
return hal_i2c_mst_write(id, device_addr, tx_buf, tx_len, NULL, true, true, false);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_simple_recv(enum HAL_I2C_ID_T id, uint16_t device_addr, const uint8_t *tx_buf, uint16_t tx_len, uint8_t *rx_buf, uint16_t rx_len)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
ret = hal_i2c_mst_write(id, device_addr, tx_buf, tx_len, NULL, true, false, false);
|
||
|
if (ret) {
|
||
|
HAL_I2C_TRACE(2,"%s: mst_write failed: ret=%d", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
return hal_i2c_mst_read(id, device_addr, rx_buf, rx_len, NULL, true, true, false);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_set_interrupt_handler(enum HAL_I2C_ID_T id, HAL_I2C_INT_HANDLER_T handler)
|
||
|
{
|
||
|
hal_i2c_int_handlers[id] = handler;
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
/* simple mode end */
|
||
|
|
||
|
/* sensor engine mode */
|
||
|
#ifdef I2C_SENSOR_ENGINE
|
||
|
static void hal_i2c_sensor_eng_proc(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
HAL_I2C_TRACE(2,"%s: id=%d", __func__, id);
|
||
|
|
||
|
uint32_t reg_base = _i2c_get_base(id);
|
||
|
uint32_t irq_status = i2cip_r_int_status(reg_base);
|
||
|
uint32_t POSSIBLY_UNUSED irq_raw_status = i2cip_r_raw_int_status(reg_base);
|
||
|
uint32_t abt_source = i2cip_r_tx_abrt_source(reg_base);
|
||
|
enum HAL_I2C_SM_TASK_STATE_T task_state;
|
||
|
|
||
|
task_state = _i2c_chk_clr_task_error(reg_base, irq_status, abt_source);
|
||
|
|
||
|
HAL_I2C_TRACE(5,"%s: id=%d irq=0x%X/0x%X abt=0x%X", __func__, id, irq_status, irq_raw_status, abt_source);
|
||
|
_i2c_show_error_code(abt_source);
|
||
|
|
||
|
if (task_state & (HAL_I2C_SM_TASK_STATE_TX_ABRT | HAL_I2C_SM_TASK_STATE_FIFO_ERR)) {
|
||
|
HAL_I2C_ERROR(6,"*** Error:%s: id=%d task_state=0x%X irq=0x%X/0x%X abt=0x%X", __func__, id, task_state, irq_status, irq_raw_status, abt_source);
|
||
|
hal_i2c_sensor_engine_stop(i2c_sensor_id[id]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _sensor_irq_handler(enum HAL_SENSOR_ENGINE_ID_T id, enum HAL_SENSOR_ENGINE_DEVICE_T device, const uint8_t *buf, uint32_t len)
|
||
|
{
|
||
|
enum HAL_I2C_ID_T i2c_id;
|
||
|
|
||
|
i2c_id = HAL_I2C_ID_0 + (device - HAL_SENSOR_ENGINE_DEVICE_I2C0);
|
||
|
ASSERT(i2c_id < HAL_I2C_ID_NUM, invalid_id, i2c_id);
|
||
|
|
||
|
if (i2c_sensor_handler[i2c_id]) {
|
||
|
i2c_sensor_handler[i2c_id](i2c_id, buf, len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_sensor_engine_start(enum HAL_I2C_ID_T id, const struct HAL_I2C_SENSOR_ENGINE_CONFIG_T *cfg)
|
||
|
{
|
||
|
enum HAL_I2C_SM_TASK_ACTION_T action;
|
||
|
const struct HAL_I2C_SM_TASK_T *out_task;
|
||
|
struct HAL_SENSOR_ENGINE_CFG_T sensor_cfg;
|
||
|
uint32_t reg_base;
|
||
|
|
||
|
HAL_I2C_ERROR(2,"%s: id=%d", __func__, id);
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.mode != HAL_I2C_API_MODE_SENSOR_ENGINE) {
|
||
|
HAL_I2C_TRACE(1,"i2c-se start: not sensor engine mode: %d", hal_i2c_sm[id].cfg.mode);
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
if (hal_i2c_sm[id].state != HAL_I2C_SM_IDLE) {
|
||
|
HAL_I2C_TRACE(1,"i2c-se start: not idle: %d", hal_i2c_sm[id].state);
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
action = HAL_I2C_SM_TASK_ACTION_M_RECV;
|
||
|
|
||
|
hal_i2c_sm[id].state = HAL_I2C_SM_RUNNING;
|
||
|
|
||
|
hal_i2c_sm_commit(id, cfg->write_buf, cfg->write_txn_len,
|
||
|
cfg->read_buf, cfg->read_txn_len, cfg->txn_cnt,
|
||
|
cfg->target_addr, action, 0, NULL);
|
||
|
|
||
|
out_task = &(hal_i2c_sm[id].task[hal_i2c_sm[id].out_task]);
|
||
|
hal_i2c_dma_config(id, out_task);
|
||
|
|
||
|
i2c_sensor_id[id] = cfg->id;
|
||
|
i2c_sensor_handler[id] = cfg->handler;
|
||
|
|
||
|
memset(&sensor_cfg, 0, sizeof(sensor_cfg));
|
||
|
sensor_cfg.id = cfg->id;
|
||
|
sensor_cfg.device = (id == HAL_I2C_ID_0) ? HAL_SENSOR_ENGINE_DEVICE_I2C0 : HAL_SENSOR_ENGINE_DEVICE_I2C1;
|
||
|
sensor_cfg.trigger_type = cfg->trigger_type;
|
||
|
sensor_cfg.trigger_gpio = cfg->trigger_gpio;
|
||
|
sensor_cfg.period_us = cfg->period_us;
|
||
|
sensor_cfg.device_address = cfg->target_addr;
|
||
|
sensor_cfg.tx_dma_cfg = &hal_i2c_sm[id].tx_dma_cfg;
|
||
|
sensor_cfg.rx_dma_cfg = &hal_i2c_sm[id].rx_dma_cfg;
|
||
|
sensor_cfg.rx_burst_len = cfg->read_txn_len * cfg->txn_cnt;
|
||
|
sensor_cfg.rx_burst_cnt = cfg->read_burst_cnt;
|
||
|
sensor_cfg.handler = _sensor_irq_handler;;
|
||
|
#ifdef I2C_VAD
|
||
|
sensor_cfg.data_to_vad = 1;
|
||
|
i2cip_w_data_to_vad(reg_base, HAL_I2C_YES);
|
||
|
#endif
|
||
|
|
||
|
hal_sensor_engine_open(&sensor_cfg);
|
||
|
|
||
|
/* tx : quarter trigger TX EMPTY INT */
|
||
|
i2cip_w_tx_threshold(reg_base, HAL_I2C_TX_TL);
|
||
|
if (action == HAL_I2C_SM_TASK_ACTION_M_RECV) {
|
||
|
/* rx : three quarter trigger RX FULL INT */
|
||
|
i2cip_w_rx_threshold(reg_base, HAL_I2C_RX_TL);
|
||
|
}
|
||
|
|
||
|
i2cip_init_int_mask(reg_base, I2CIP_INT_MASK_ERROR_MASK);
|
||
|
|
||
|
i2cip_w_restart(reg_base, HAL_I2C_YES);
|
||
|
i2cip_w_target_address(reg_base, out_task->target_addr);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_i2c_sensor_engine_stop(enum HAL_I2C_ID_T id)
|
||
|
{
|
||
|
uint32_t reg_base;
|
||
|
uint32_t irq_status;
|
||
|
uint32_t abt_source;
|
||
|
|
||
|
HAL_I2C_ERROR(2,"%s: id=%d", __func__, id);
|
||
|
ASSERT(id < HAL_I2C_ID_NUM, invalid_id, id);
|
||
|
|
||
|
if (hal_i2c_sm[id].cfg.mode != HAL_I2C_API_MODE_SENSOR_ENGINE) {
|
||
|
HAL_I2C_TRACE(1,"i2c-se stop: not sensor engine mode: %d", hal_i2c_sm[id].cfg.mode);
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
if (hal_i2c_sm[id].state != HAL_I2C_SM_RUNNING) {
|
||
|
HAL_I2C_TRACE(1,"i2c-se stop: not running: %d", hal_i2c_sm[id].state);
|
||
|
return HAL_I2C_ERRCODE_INV_PARAM;
|
||
|
}
|
||
|
|
||
|
hal_sensor_engine_close(i2c_sensor_id[id]);
|
||
|
|
||
|
hal_i2c_dma_release(id);
|
||
|
|
||
|
reg_base = _i2c_get_base(id);
|
||
|
|
||
|
HAL_I2C_TRACE(0,"disable i2c");
|
||
|
i2cip_w_enable(reg_base, HAL_I2C_NO);
|
||
|
|
||
|
irq_status = i2cip_r_int_status(reg_base);
|
||
|
abt_source = i2cip_r_tx_abrt_source(reg_base);
|
||
|
_i2c_chk_clr_task_error(reg_base, irq_status, abt_source);
|
||
|
|
||
|
#ifdef I2C_VAD
|
||
|
i2cip_w_data_to_vad(reg_base, HAL_I2C_NO);
|
||
|
#endif
|
||
|
|
||
|
hal_i2c_sm_done(id);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
/* sensor engine mode end */
|
||
|
|
||
|
/* gpio iic mode */
|
||
|
#include "hal_gpio.h"
|
||
|
|
||
|
static uint8_t g_i2c_open = false;
|
||
|
|
||
|
#define DURATION_INIT_1 600
|
||
|
#define DURATION_INIT_2 600
|
||
|
#define DURATION_INIT_3 600
|
||
|
|
||
|
#define DURATION_START_1 600
|
||
|
#define DURATION_START_2 600
|
||
|
#define DURATION_START_3 600
|
||
|
|
||
|
#define DURATION_STOP_1 800
|
||
|
#define DURATION_STOP_2 600
|
||
|
#define DURATION_STOP_3 1300
|
||
|
|
||
|
#define DURATION_HIGH 900
|
||
|
#define DURATION_LOW 600
|
||
|
|
||
|
#define HAL_GPIO_I2C_DELAY(duration) hal_sys_timer_delay_ns(duration);
|
||
|
|
||
|
struct HAL_GPIO_I2C_CONFIG_T hal_gpio_i2c_cfg;
|
||
|
|
||
|
inline void GPIO_InitIO(uint8_t port, uint8_t direction, uint8_t val_for_out)
|
||
|
{
|
||
|
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)port, (enum HAL_GPIO_DIR_T)direction, val_for_out);
|
||
|
}
|
||
|
|
||
|
inline void GPIO_WriteIO(uint8_t port, uint8_t data)
|
||
|
{
|
||
|
if(data){
|
||
|
hal_gpio_pin_set((enum HAL_GPIO_PIN_T)port);
|
||
|
}else{
|
||
|
hal_gpio_pin_clr((enum HAL_GPIO_PIN_T)port);
|
||
|
}
|
||
|
}
|
||
|
inline uint8_t GPIO_ReadIO(uint8_t port)
|
||
|
{
|
||
|
uint8_t level = 0;
|
||
|
level = hal_gpio_pin_get_val((enum HAL_GPIO_PIN_T)port);
|
||
|
return level;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
//-------------------------------------------------------------------
|
||
|
// Function: gpio_i2c_init
|
||
|
// Purpose: This function is used to init I2C port of the device
|
||
|
// In:
|
||
|
// Return: bool
|
||
|
//-------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
static int hal_gpio_i2c_initialize(const struct HAL_GPIO_I2C_CONFIG_T *cfg)
|
||
|
{
|
||
|
struct HAL_IOMUX_PIN_FUNCTION_MAP hal_gpio_i2c_iomux_cfg[] = {
|
||
|
{HAL_IOMUX_PIN_NUM, HAL_IOMUX_FUNC_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE},
|
||
|
{HAL_IOMUX_PIN_NUM, HAL_IOMUX_FUNC_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE},
|
||
|
};
|
||
|
|
||
|
hal_gpio_i2c_cfg.scl = cfg->scl;
|
||
|
hal_gpio_i2c_cfg.sda = cfg->sda;
|
||
|
hal_gpio_i2c_iomux_cfg[0].pin = (enum HAL_IOMUX_PIN_T)hal_gpio_i2c_cfg.scl;
|
||
|
hal_gpio_i2c_iomux_cfg[1].pin = (enum HAL_IOMUX_PIN_T)hal_gpio_i2c_cfg.sda;
|
||
|
hal_iomux_init((struct HAL_IOMUX_PIN_FUNCTION_MAP *)hal_gpio_i2c_iomux_cfg, sizeof(hal_gpio_i2c_iomux_cfg)/sizeof(struct HAL_IOMUX_PIN_FUNCTION_MAP));
|
||
|
|
||
|
HAL_I2C_TRACE(2,"hal_gpio_i2c_initialize scl=%d sda=%d", hal_gpio_i2c_cfg.scl , hal_gpio_i2c_cfg.sda);
|
||
|
//iTemp = hal_gpio_i2c_cfg.scl | hal_gpio_i2c_cfg.sda ;
|
||
|
// Set the GPIO pin to output status
|
||
|
GPIO_InitIO(hal_gpio_i2c_cfg.scl, 1, 1);
|
||
|
GPIO_InitIO(hal_gpio_i2c_cfg.sda, 1, 1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_INIT_1);
|
||
|
|
||
|
// Make the I2C bus in idle status
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_INIT_1);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_INIT_1);
|
||
|
|
||
|
for(byte i=0;i<30;i++)
|
||
|
{
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0); /* low */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_HIGH);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void hal_gpio_i2c_start(void) /* start or re-start */
|
||
|
{
|
||
|
GPIO_InitIO(hal_gpio_i2c_cfg.sda, 1, 1);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,1);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1);
|
||
|
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_START_1);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_START_2);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_START_3);/* start condition */
|
||
|
}
|
||
|
|
||
|
static void hal_gpio_i2c_stop(void)
|
||
|
{
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
GPIO_InitIO(hal_gpio_i2c_cfg.sda, 1, 0);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_STOP_1);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_STOP_2);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,1); /* stop condition */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_STOP_3);
|
||
|
}
|
||
|
|
||
|
static uint8_t hal_gpio_i2c_txbyte(uint8_t data) /* return 0 --> ack */
|
||
|
{
|
||
|
int i;
|
||
|
uint8_t temp_value = 0;
|
||
|
for(i=7; (i>=0)&&(i<=7); i--)
|
||
|
{
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0); /* low */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
if(i==7)GPIO_InitIO(hal_gpio_i2c_cfg.sda, 1, 0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,((data>>i)&0x01));
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW/2);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl, 1); /* high */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_HIGH);
|
||
|
}
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0); /* low */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
GPIO_InitIO(hal_gpio_i2c_cfg.sda, 0, 1);/* input */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW/2);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1); /* high */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_HIGH);
|
||
|
temp_value = GPIO_ReadIO(hal_gpio_i2c_cfg.sda );
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0); /* low */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
return temp_value;
|
||
|
}
|
||
|
|
||
|
static void hal_gpio_i2c_rxbyte(uint8_t *data, uint8_t ack)
|
||
|
{
|
||
|
int i;
|
||
|
uint32_t dataCache;
|
||
|
|
||
|
dataCache = 0;
|
||
|
for(i=7; (i>=0)&&(i<=7); i--)
|
||
|
{
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
if(i==7)GPIO_InitIO(hal_gpio_i2c_cfg.sda, 0, 1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_HIGH);
|
||
|
dataCache |= (GPIO_ReadIO(hal_gpio_i2c_cfg.sda )<<i);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW/2);
|
||
|
}
|
||
|
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
GPIO_InitIO(hal_gpio_i2c_cfg.sda, 1, 1);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.sda ,ack);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW/2);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,1);
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_HIGH);
|
||
|
GPIO_WriteIO(hal_gpio_i2c_cfg.scl,0); /* low */
|
||
|
HAL_GPIO_I2C_DELAY(DURATION_LOW);
|
||
|
*data = (uint8_t)dataCache;
|
||
|
}
|
||
|
|
||
|
|
||
|
uint32_t hal_gpio_i2c_simple_send(uint32_t device_addr, const uint8_t *tx_buf, uint16_t tx_len)
|
||
|
{
|
||
|
uint32_t i;
|
||
|
|
||
|
hal_gpio_i2c_start();
|
||
|
if (device_addr & HAL_I2C_10BITADDR_MASK) {
|
||
|
hal_gpio_i2c_txbyte(0xF0 | ((device_addr & 0x200) >> 7));
|
||
|
hal_gpio_i2c_txbyte(device_addr & 0xFF);
|
||
|
} else {
|
||
|
hal_gpio_i2c_txbyte((device_addr & 0x7F) << 1);
|
||
|
}
|
||
|
for (i = 0; i < tx_len; i++, tx_buf++) {
|
||
|
hal_gpio_i2c_txbyte(*tx_buf);
|
||
|
}
|
||
|
hal_gpio_i2c_stop();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_gpio_i2c_simple_recv(uint32_t device_addr, const uint8_t *tx_buf, uint16_t tx_len, uint8_t *rx_buf, uint16_t rx_len)
|
||
|
{
|
||
|
uint8_t tempdata;
|
||
|
uint32_t i;
|
||
|
|
||
|
if (tx_len) {
|
||
|
hal_gpio_i2c_start();
|
||
|
if (device_addr & HAL_I2C_10BITADDR_MASK) {
|
||
|
hal_gpio_i2c_txbyte(((device_addr & 0x200) >> 7) | 0xF0);
|
||
|
hal_gpio_i2c_txbyte(device_addr & 0xFF);
|
||
|
} else {
|
||
|
hal_gpio_i2c_txbyte((device_addr & 0x7F) << 1);
|
||
|
}
|
||
|
for (i = 0; i < tx_len; i++, tx_buf++) {
|
||
|
hal_gpio_i2c_txbyte(*tx_buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hal_gpio_i2c_start();
|
||
|
if (device_addr & HAL_I2C_10BITADDR_MASK) {
|
||
|
hal_gpio_i2c_txbyte(((device_addr & 0x200) >> 7) | 0xF1);
|
||
|
} else {
|
||
|
hal_gpio_i2c_txbyte(((device_addr & 0x7F) << 1) | 1);
|
||
|
}
|
||
|
for (i = 0; i < rx_len; i++, rx_buf++) {
|
||
|
hal_gpio_i2c_rxbyte(&tempdata, (i == rx_len - 1));
|
||
|
*rx_buf = tempdata;
|
||
|
}
|
||
|
hal_gpio_i2c_stop();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define touch_ic_device_addr 0x60
|
||
|
unsigned char I2C_WriteByte(unsigned char reg, unsigned char data)
|
||
|
{
|
||
|
unsigned char result;
|
||
|
unsigned char buff[2];
|
||
|
|
||
|
buff[0] = reg;
|
||
|
buff[1] = data;
|
||
|
|
||
|
result = hal_gpio_i2c_simple_send((unsigned char)touch_ic_device_addr,buff,2);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
unsigned char I2C_ReadByte(unsigned char reg, unsigned char* data)
|
||
|
{
|
||
|
unsigned char result;
|
||
|
|
||
|
result = hal_gpio_i2c_simple_recv((unsigned char)touch_ic_device_addr,®,1,data,1);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int hal_gpio_i2c_open(const struct HAL_GPIO_I2C_CONFIG_T *cfg)
|
||
|
{
|
||
|
static bool i2cInitDone = false;
|
||
|
int lock;
|
||
|
|
||
|
if (g_i2c_open == true)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
lock = int_lock();
|
||
|
g_i2c_open = 0;
|
||
|
int_unlock(lock);
|
||
|
|
||
|
if (!i2cInitDone)
|
||
|
{
|
||
|
hal_gpio_i2c_initialize(cfg);
|
||
|
i2cInitDone = 0;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int hal_gpio_i2c_close(void)
|
||
|
{
|
||
|
int lock;
|
||
|
|
||
|
if (g_i2c_open == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
lock = int_lock();
|
||
|
g_i2c_open = false;
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint32_t hal_gpio_i2c_send(uint32_t device_addr, const uint8_t *buf, uint32_t reg_len, uint32_t value_len)
|
||
|
{
|
||
|
return hal_gpio_i2c_simple_send(device_addr, buf, reg_len + value_len);
|
||
|
}
|
||
|
|
||
|
uint32_t hal_gpio_i2c_recv(uint32_t device_addr, uint8_t *buf, uint32_t reg_len, uint32_t value_len, uint8_t restart_after_write)
|
||
|
{
|
||
|
return hal_gpio_i2c_simple_recv(device_addr, buf, reg_len, buf+reg_len, value_len);
|
||
|
}
|
||
|
/* gpio iic end */
|
||
|
|
||
|
int app_i2c_demo_init(void)
|
||
|
{
|
||
|
static struct HAL_GPIO_I2C_CONFIG_T i2c_cfg={
|
||
|
HAL_GPIO_PIN_P2_0,
|
||
|
HAL_GPIO_PIN_P2_1,
|
||
|
0,
|
||
|
};
|
||
|
hal_gpio_i2c_open(&i2c_cfg);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|