diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_physical_layer.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_physical_layer.c | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_physical_layer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_physical_layer.c new file mode 100644 index 0000000..8067685 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_physical_layer.c @@ -0,0 +1,742 @@ +/** +* \copyright +* Copyright (c) 2018, Infineon Technologies AG +* All rights reserved. +* +* This software is provided with terms and conditions as specified in OPTIGA(TM) Trust X Evaluation Kit License Agreement. +* \endcopyright +* +* \author Infineon AG +* +* \file ifx_i2c_physical_layer.c +* +* \brief This file implements the IFX I2C Physical Layer. +* +* \addtogroup grIFXI2C +* @{ +*/ + +/*********************************************************************************************************************** +* HEADER FILES +**********************************************************************************************************************/ +#include "ifx_i2c_physical_layer.h" +#include "pal_os_event.h" + +/// @cond hidden +/*********************************************************************************************************************** +* MACROS +**********************************************************************************************************************/ +// Physical Layer Register addresses +#define PL_REG_DATA (0x80) +#define PL_REG_DATA_REG_LEN (0x81) +#define PL_REG_I2C_STATE (0x82) +#define PL_REG_BASE_ADDR (0x83) +#define PL_REG_MAX_SCL_FREQU (0x84) +#define PL_REG_SOFT_RESET (0x88) +#define PL_REG_I2C_MODE (0x89) + +// Physical Layer Register lengths +#define PL_REG_LEN_I2C_STATE (4) +#define PL_REG_LEN_MAX_SCL_FREQU (4) +#define PL_REG_LEN_I2C_MODE (2) +#define PL_REG_LEN_DATA_REG_LEN (2) +#define PL_REG_LEN_SOFT_RESET (2) +#define PL_REG_LEN_BASE_ADDR (2) + +// Physical Layer State Register masks +#define PL_REG_I2C_STATE_RESPONSE_READY (0x40) +#define PL_REG_I2C_STATE_SOFT_RESET (0x08) + +// Physical Layer low level interface constants +#define PL_ACTION_READ_REGISTER (0x01) +#define PL_ACTION_WRITE_REGISTER (0x02) +#define PL_I2C_CMD_WRITE (0x01) +#define PL_I2C_CMD_READ (0x02) + +// Physical Layer high level interface constants +#define PL_ACTION_WRITE_FRAME (0x01) +#define PL_ACTION_READ_FRAME (0x02) +#define PL_STATE_UNINIT (0x00) +#define PL_STATE_INIT (0x01) +#define PL_STATE_READY (0x02) +#define PL_STATE_DATA_AVAILABLE (0x03) +#define PL_STATE_RXTX (0x04) +#define PL_STATE_SOFT_RESET (0x05) + +//Physical Layer negotiation constants +#define PL_INIT_SET_DATA_REG_LEN (0x11) +#define PL_INIT_GET_DATA_REG_LEN (0x22) +#define PL_INIT_GET_FREQ_REG (0x33) +#define PL_INIT_SET_FREQ_REG (0x44) +#define PL_INIT_READ_FREQ (0x55) +#define PL_INIT_VERIFY_FREQ (0x66) +#define PL_INIT_AGREE_FREQ (0x77) +#define PL_INIT_VERIFY_DATA_REG (0x88) +#define PL_INIT_GET_STATUS_REG (0x99) +#define PL_INIT_DONE (0xAA) +#define PL_INIT_SET_FREQ_DEFAULT (0xBB) + +//Physical layer soft reset states +#define PL_RESET_INIT (0xA1) +#define PL_RESET_WRITE (0xA2) +#define PL_RESET_STARTUP (0xA3) + +#define PL_REG_I2C_MODE_PERSISTANT (0x80) +#define PL_REG_I2C_MODE_SM_FM (0x03) +#define PL_REG_I2C_MODE_FM_PLUS (0x04) +#define PL_SM_FM_MAX_FREQUENCY (0x190) +#define PL_DEFAULT_FREQUENCY (0x64) +#define PL_REG_BASE_ADDR_PERSISTANT (0x80) +#define PL_REG_BASE_ADDR_VOLATILE (0x00) + +// Physical Layer Base Address Register mask +#define PL_REG_I2C_BASE_ADDRESS_MASK (0x7F) + +// Setup debug log statements +#if IFX_I2C_LOG_PL == 1 +#define LOG_PL IFX_I2C_LOG +#else +#define LOG_PL(...) //printf(__VA_ARGS__) +#endif +/*********************************************************************************************************************** +* ENUMS +**********************************************************************************************************************/ +/*********************************************************************************************************************** +* DATA STRUCTURES +***********************************************************************************************************************/ +/*********************************************************************************************************************** +* GLOBAL +***********************************************************************************************************************/ + +static host_lib_status_t pal_event_status; + +/*********************************************************************************************************************** +* LOCAL ROUTINES +***********************************************************************************************************************/ +/// Physical Layer low level interface function +static void ifx_i2c_pl_read_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len); +/// Physical Layer low level interface function +static void ifx_i2c_pl_write_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len, const uint8_t* p_content); +/// Physical Layer high level interface timer callback (Status register polling) +static void ifx_i2c_pl_status_poll_callback(void *p_ctx); +/// Physical Layer intermediate state machine (Negotiation with slave) +static void ifx_i2c_pl_negotiation_event_handler(void *p_input_ctx); +/// Physical Layer intermediate state machine(Set bit rate) +static host_lib_status_t ifx_i2c_pl_set_bit_rate(ifx_i2c_context_t *p_ctx, uint16_t bitrate); +/// Physical Layer intermediate state machine (soft reset) +static void ifx_i2c_pl_soft_reset(ifx_i2c_context_t *p_ctx); +/// Physical Layer high level interface state machine (read/write frames) +static void ifx_i2c_pl_frame_event_handler(ifx_i2c_context_t *p_ctx,host_lib_status_t event); +/// Physical Layer low level interface timer callback (I2C Nack/Busy polling) +static void ifx_i2c_pal_poll_callback(void *p_ctx); +/// Physical Layer low level guard time callback +static void ifx_i2c_pl_guard_time_callback(void *p_ctx); +/// Physical Layer low level interface state machine (read/write registers) +static void ifx_i2c_pl_pal_event_handler(void *p_ctx, host_lib_status_t event); +/// Physical layer low level event handler for set slave address +static void ifx_i2c_pl_pal_slave_addr_event_handler(void *p_input_ctx, host_lib_status_t event); + +/// @endcond +/*********************************************************************************************************************** +* API PROTOTYPES +**********************************************************************************************************************/ +/// Physical Layer high level interface function +host_lib_status_t ifx_i2c_pl_init(ifx_i2c_context_t *p_ctx,ifx_i2c_event_handler_t handler) +{ + LOG_PL("[IFX-PL]: Init\n"); + + p_ctx->pl.upper_layer_event_handler = handler; + p_ctx->pl.frame_state = PL_STATE_UNINIT; + p_ctx->pl.negotiate_state = PL_INIT_SET_FREQ_DEFAULT; + p_ctx->p_pal_i2c_ctx->slave_address = p_ctx->slave_address; + p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = (void *) ifx_i2c_pl_pal_event_handler; + p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; + if(TRUE == p_ctx->do_pal_init) + { + // Initialize I2C driver + if (PAL_STATUS_SUCCESS != pal_i2c_init(p_ctx->p_pal_i2c_ctx)) + { + return IFX_I2C_STACK_ERROR; + } + } + // Set Physical Layer internal state + if(p_ctx->pl.request_soft_reset == (uint8_t)TRUE) + { + //Set the soft reset request to initial state to read register + p_ctx->pl.request_soft_reset = PL_INIT_GET_STATUS_REG; + p_ctx->pl.frame_state = PL_STATE_SOFT_RESET; + } + else + { + p_ctx->pl.frame_state = PL_STATE_INIT; + } + + ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); + + return IFX_I2C_STACK_SUCCESS; +} + +/// Physical Layer high level interface function +host_lib_status_t ifx_i2c_pl_send_frame(ifx_i2c_context_t *p_ctx,uint8_t* p_frame, uint16_t frame_len) +{ + // Physical Layer must be idle, set requested action + if (p_ctx->pl.frame_state != PL_STATE_INIT && p_ctx->pl.frame_state != PL_STATE_READY) + { + return IFX_I2C_STACK_ERROR; + } + p_ctx->pl.frame_action = PL_ACTION_WRITE_FRAME; + + // Store reference to frame for sending it later + p_ctx->pl.p_tx_frame = p_frame; + p_ctx->pl.tx_frame_len = frame_len; + + ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); + return IFX_I2C_STACK_SUCCESS; +} + +/// Physical Layer high level interface function +host_lib_status_t ifx_i2c_pl_receive_frame(ifx_i2c_context_t *p_ctx) +{ + // Physical Layer must be idle, set requested action + if (p_ctx->pl.frame_state != PL_STATE_INIT && p_ctx->pl.frame_state != PL_STATE_READY) + { + return IFX_I2C_STACK_ERROR; + } + p_ctx->pl.frame_action = PL_ACTION_READ_FRAME; + + ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); + return IFX_I2C_STACK_SUCCESS; +} + +host_lib_status_t ifx_i2c_pl_write_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t persistent) +{ + host_lib_status_t status = IFX_I2C_STACK_ERROR; + app_event_handler_t * temp_upper_layer_event_handler; + + /// @cond hidden + #define PAL_WRITE_INIT_STATUS (0x00FF) + #define ADDRESS_OFFSET (0x02) + #define BASE_ADDRESS_REG_OFFSET (0x00) + #define MODE_OFFSET (0x01) + #define POLLING_INTERVAL (0x01) + #define DELAY_FOR_COMPLETION (0x0A) + /// @endcond + + //lint --e{611} suppress "void* function pointer is type casted to app_event_handler_t type" + //ifx i2c wrapper api for setting slave address in synchronous. hence the event handler is backed up. + temp_upper_layer_event_handler = (app_event_handler_t *)(p_ctx->p_pal_i2c_ctx->upper_layer_event_handler); + //since the lower level APIs are asynchronous, a temporary event handler for set slave address is assigned + p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = (void *) ifx_i2c_pl_pal_slave_addr_event_handler; + + p_ctx->pl.buffer[BASE_ADDRESS_REG_OFFSET] = PL_REG_BASE_ADDR; + p_ctx->pl.buffer[MODE_OFFSET] = PL_REG_BASE_ADDR_VOLATILE; + //supported base addresses are 0x00 - 0x7F. Hence 8th bit is ignored + p_ctx->pl.buffer[ADDRESS_OFFSET] = slave_address & PL_REG_I2C_BASE_ADDRESS_MASK; + p_ctx->pl.buffer_tx_len = 1 + PL_REG_LEN_BASE_ADDR; + + if(PL_REG_BASE_ADDR_VOLATILE != persistent) + { + p_ctx->pl.buffer[MODE_OFFSET] = PL_REG_BASE_ADDR_PERSISTANT; + } + + p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; + + while(p_ctx->pl.retry_counter) + { + pal_event_status = PAL_WRITE_INIT_STATUS; + + //lint --e{534} suppress "Return value is not required to be checked" + pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len); + while(PAL_WRITE_INIT_STATUS == pal_event_status){}; + if(PAL_I2C_EVENT_SUCCESS == pal_event_status) + { + break; + } + p_ctx->pl.retry_counter--; + pal_os_timer_delay_in_milliseconds(POLLING_INTERVAL); + } + + if(PAL_I2C_EVENT_SUCCESS == pal_event_status) + { + p_ctx->p_pal_i2c_ctx->slave_address = p_ctx->pl.buffer[ADDRESS_OFFSET]; + if(PL_REG_BASE_ADDR_VOLATILE != persistent) + { + p_ctx->slave_address = p_ctx->pl.buffer[ADDRESS_OFFSET]; + } + pal_os_timer_delay_in_milliseconds(DELAY_FOR_COMPLETION); + status = IFX_I2C_STACK_SUCCESS; + } + //restoring the backed up event handler + p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = temp_upper_layer_event_handler; + + /// @cond hidden + #undef PAL_WRITE_INIT_STATUS + #undef ADDRESS_OFFSET + #undef BASE_ADDRESS_REG_OFFSET + #undef MODE_OFFSET + #undef POLLING_INTERVAL + #undef DELAY_FOR_COMPLETION + /// @endcond + + return status; +} + +static void ifx_i2c_pl_read_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len) +{ + LOG_PL("[IFX-PL]: Read register %x len %d\n", reg_addr, reg_len); + + // Prepare transmit buffer to write register address + p_ctx->pl.buffer[0] = reg_addr; + p_ctx->pl.buffer_tx_len = 1; + + // Set low level interface variables and start transmission + p_ctx->pl.buffer_rx_len = reg_len; + p_ctx->pl.register_action = PL_ACTION_READ_REGISTER; + p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; + p_ctx->pl.i2c_cmd = PL_I2C_CMD_WRITE; + + //lint --e{534} suppress "Return value is not required to be checked" + pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len); +} + + +static void ifx_i2c_pl_write_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len, const uint8_t* p_content) +{ + LOG_PL("[IFX-PL]: Write register %x len %d\n", reg_addr, reg_len); + + // Prepare transmit buffer to write register address and content + p_ctx->pl.buffer[0] = reg_addr; + memcpy(p_ctx->pl.buffer + 1, p_content, reg_len); + p_ctx->pl.buffer_tx_len = 1 + reg_len; + + // Set Physical Layer low level interface variables and start transmission + p_ctx->pl.register_action = PL_ACTION_WRITE_REGISTER; + p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; + p_ctx->pl.i2c_cmd = PL_I2C_CMD_WRITE; + //lint --e{534} suppress "Return value is not required to be checked" + pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len); +} + + +static void ifx_i2c_pl_status_poll_callback(void *p_ctx) +{ + LOG_PL("[IFX-PL]: Status poll Timer elapsed -> Read STATUS register\n"); + ifx_i2c_pl_read_register((ifx_i2c_context_t*)p_ctx,PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE); +} + +static host_lib_status_t ifx_i2c_pl_set_bit_rate(ifx_i2c_context_t *p_ctx, uint16_t bitrate) +{ + host_lib_status_t status; + void* pal_ctx_upper_layer_handler; + // Save upper layer context in pal + pal_ctx_upper_layer_handler = p_ctx->p_pal_i2c_ctx->upper_layer_event_handler; + // Pass context as NULL to avoid callback invocation + p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = NULL; + status = pal_i2c_set_bitrate(p_ctx->p_pal_i2c_ctx , bitrate); + // Restore callback + p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = pal_ctx_upper_layer_handler; + if(PAL_I2C_EVENT_SUCCESS != status) + { + if (p_ctx->pl.retry_counter--) + { + LOG_PL("[IFX-PL]: Set bit rate failed, Retry setting.\n"); + pal_os_event_register_callback_oneshot(ifx_i2c_pl_negotiation_event_handler,((void*)p_ctx),PL_POLLING_INVERVAL_US); + status = IFX_I2C_STACK_BUSY; + } + else + { + status = IFX_I2C_STACK_ERROR; + } + } + else + { + status = IFX_I2C_STACK_SUCCESS; + } + + return status; + +} +static void ifx_i2c_pl_negotiation_event_handler(void *p_input_ctx) +{ + host_lib_status_t event = (uint8_t)IFX_I2C_STACK_ERROR; + uint8_t continue_negotiation; + ifx_i2c_context_t* p_ctx = (ifx_i2c_context_t*)p_input_ctx; + uint8_t i2c_mode_value[2]; + uint8_t max_frame_size[2] = { (uint8_t)(p_ctx->frame_size >> 8), (uint8_t)(p_ctx->frame_size) }; + uint16_t buffer_len = 0; + uint16_t slave_frequency; + uint16_t slave_frame_len; + uint8_t* p_buffer = NULL; + + do + { + continue_negotiation = FALSE; + LOG_PL("[IFX-PL]: Negotiation started\n"); + switch(p_ctx->pl.negotiate_state) + { + // Set initial frequency to PL_DEFAULT_FREQUENCY to be able to negotiate with slave + case PL_INIT_SET_FREQ_DEFAULT: + { + // Default frequency set to master + event = ifx_i2c_pl_set_bit_rate(p_input_ctx,PL_DEFAULT_FREQUENCY); + if(IFX_I2C_STACK_SUCCESS == event) + { + p_ctx->pl.negotiate_state = PL_INIT_GET_FREQ_REG; + continue_negotiation = TRUE; + } + else if (IFX_I2C_STACK_ERROR == event) + { + p_ctx->pl.negotiate_state = PL_INIT_DONE; + p_buffer = NULL; + buffer_len = 0; + } + } + break; + // Read the current Max frequency supported by slave + case PL_INIT_GET_FREQ_REG: + { + p_ctx->pl.negotiate_state = PL_INIT_SET_FREQ_REG; + ifx_i2c_pl_read_register(p_ctx,PL_REG_MAX_SCL_FREQU, PL_REG_LEN_MAX_SCL_FREQU); + } + break; + // Set the I2C mode register + case PL_INIT_SET_FREQ_REG: + { + slave_frequency = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3]; + + i2c_mode_value[0] = PL_REG_I2C_MODE_PERSISTANT; + if((p_ctx->frequency > PL_SM_FM_MAX_FREQUENCY)&&(slave_frequency<=PL_SM_FM_MAX_FREQUENCY)) + { + //Change to FM+ mode if slave's current supported frequency is below user's requested frequency + i2c_mode_value[1] = PL_REG_I2C_MODE_FM_PLUS; + p_ctx->pl.negotiate_state = PL_INIT_READ_FREQ; + ifx_i2c_pl_write_register(p_ctx,PL_REG_I2C_MODE, PL_REG_LEN_I2C_MODE, i2c_mode_value); + } + else if((p_ctx->frequency <= PL_SM_FM_MAX_FREQUENCY)&&(slave_frequency>PL_SM_FM_MAX_FREQUENCY)) + { + //Change to SM&FM mode if slave's current supported frequency is above user's requested frequency + i2c_mode_value[1] = PL_REG_I2C_MODE_SM_FM; + p_ctx->pl.negotiate_state = PL_INIT_READ_FREQ; + ifx_i2c_pl_write_register(p_ctx,PL_REG_I2C_MODE, PL_REG_LEN_I2C_MODE, i2c_mode_value); + } + else + { + p_ctx->pl.negotiate_state = PL_INIT_VERIFY_FREQ; + continue_negotiation = TRUE; + } + } + break; + // After setting I2C mode register, read the slave's supported frequency + case PL_INIT_READ_FREQ: + { + p_ctx->pl.negotiate_state = PL_INIT_VERIFY_FREQ; + ifx_i2c_pl_read_register(p_ctx,PL_REG_MAX_SCL_FREQU, PL_REG_LEN_MAX_SCL_FREQU); + } + break; + // Verify the requested frequency and slave's supported frequency + case PL_INIT_VERIFY_FREQ: + { + slave_frequency = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3]; + if(p_ctx->frequency > slave_frequency) + { + LOG_PL("[IFX-PL]: Unexpected frequency in MAX_SCL_FREQU\n"); + p_buffer = NULL; + buffer_len = 0; + p_ctx->pl.negotiate_state = PL_INIT_DONE; + } + else + { + p_ctx->pl.negotiate_state = PL_INIT_AGREE_FREQ; + } + continue_negotiation = TRUE; + } + break; + // Frequency negotiated, Set frequency at master + case PL_INIT_AGREE_FREQ: + { + // Frequency negotiation between master and slave is complete + event = ifx_i2c_pl_set_bit_rate(p_input_ctx, p_ctx->frequency); + if(IFX_I2C_STACK_SUCCESS == event) + { + p_ctx->pl.negotiate_state = PL_INIT_SET_DATA_REG_LEN; + continue_negotiation = TRUE; + } + else if (IFX_I2C_STACK_ERROR == event) + { + p_ctx->pl.negotiate_state = PL_INIT_DONE; + p_buffer = NULL; + buffer_len = 0; + } + } + break; + // Start frame length negotiation by writing the requested frame length + case PL_INIT_SET_DATA_REG_LEN: + { + p_ctx->pl.negotiate_state = PL_INIT_GET_DATA_REG_LEN; + ifx_i2c_pl_write_register(p_ctx,PL_REG_DATA_REG_LEN, sizeof(max_frame_size), max_frame_size); + } + break; + // Read the frame length to verify + case PL_INIT_GET_DATA_REG_LEN: + { + p_ctx->pl.negotiate_state = PL_INIT_VERIFY_DATA_REG; + ifx_i2c_pl_read_register(p_ctx,PL_REG_DATA_REG_LEN,PL_REG_LEN_DATA_REG_LEN); + } + break; + // Check is slave accepted the new frame length + case PL_INIT_VERIFY_DATA_REG: + { + p_ctx->pl.negotiate_state = PL_INIT_DONE; + slave_frame_len = (p_ctx->pl.buffer[0] << 8) | p_ctx->pl.buffer[1]; + // Error if slave's frame length is more than requested frame length + if(p_ctx->frame_size >= slave_frame_len) + { + p_ctx->frame_size = slave_frame_len; + event = IFX_I2C_STACK_SUCCESS; + } + p_buffer = NULL; + buffer_len = 0; + continue_negotiation = TRUE; + } + break; + case PL_INIT_DONE: + { + if(IFX_I2C_STACK_SUCCESS == event) + { + p_ctx->pl.frame_state = PL_STATE_READY; + } + else + { + p_ctx->pl.frame_state = PL_STATE_UNINIT; + } + // Negotiation between master and slave is complete + p_ctx->pl.upper_layer_event_handler(p_ctx,event, p_buffer, buffer_len); + } + break; + default: + break; + } + }while(continue_negotiation); +} + + +static void ifx_i2c_pl_frame_event_handler(ifx_i2c_context_t *p_ctx,host_lib_status_t event) +{ + uint16_t frame_size; + if (event != IFX_I2C_STACK_SUCCESS) + { + p_ctx->pl.frame_state = PL_STATE_READY; + // I2C read or write failed, report to upper layer + p_ctx->pl.upper_layer_event_handler(p_ctx,event, 0, 0); + } + else + { + switch(p_ctx->pl.frame_state) + { + // Perform soft reset + case PL_STATE_SOFT_RESET: + { + ifx_i2c_pl_soft_reset(p_ctx); + } + break; + // Negotiate frame and frequency with slave + case PL_STATE_INIT: + { + ifx_i2c_pl_negotiation_event_handler(p_ctx); + } + break; + // Check status of slave data + case PL_STATE_READY: + { + // Start polling status register + p_ctx->pl.frame_state = PL_STATE_DATA_AVAILABLE; + ifx_i2c_pl_read_register(p_ctx,PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE); + } + break; + // Do read/write frame + case PL_STATE_DATA_AVAILABLE: + { + // Read frame, if response is ready. Ignore busy flag + if ((p_ctx->pl.frame_action == PL_ACTION_READ_FRAME) + && (p_ctx->pl.buffer[0] & PL_REG_I2C_STATE_RESPONSE_READY)) + { + frame_size = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3]; + if ((frame_size > 0) && (frame_size <= p_ctx->frame_size)) + { + p_ctx->pl.frame_state = PL_STATE_RXTX; + ifx_i2c_pl_read_register(p_ctx,PL_REG_DATA, frame_size); + } + else + { + // Continue polling STATUS register if retry limit is not reached + if ((pal_os_timer_get_time_in_milliseconds() - p_ctx->dl.frame_start_time) < p_ctx->dl.data_poll_timeout) + { + pal_os_event_register_callback_oneshot(ifx_i2c_pl_status_poll_callback, (void *)p_ctx, PL_DATA_POLLING_INVERVAL_US); + } + else + { + p_ctx->pl.frame_state = PL_STATE_READY; + p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_ERROR, 0, 0); + } + } + } + // Write frame is slave is not busy + else if (p_ctx->pl.frame_action == PL_ACTION_WRITE_FRAME) + { + // Write frame if device is not busy, otherwise wait and poll STATUS again later + p_ctx->pl.frame_state = PL_STATE_RXTX; + ifx_i2c_pl_write_register(p_ctx,PL_REG_DATA, p_ctx->pl.tx_frame_len, (uint8_t*)p_ctx->pl.p_tx_frame); + } + // Continue checking the slave status register + else + { + // Continue polling STATUS register if retry limit is not reached + if ((pal_os_timer_get_time_in_milliseconds() - p_ctx->dl.frame_start_time) < p_ctx->dl.data_poll_timeout) + { + pal_os_event_register_callback_oneshot(ifx_i2c_pl_status_poll_callback, (void *)p_ctx, PL_DATA_POLLING_INVERVAL_US); + } + else + { + p_ctx->pl.frame_state = PL_STATE_READY; + p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_ERROR, 0, 0); + } + } + } + break; + // Frame reading is complete + case PL_STATE_RXTX: + { + // Writing/reading of frame to/from DATA register complete + p_ctx->pl.frame_state = PL_STATE_READY; + p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS, p_ctx->pl.buffer, p_ctx->pl.buffer_rx_len); + } + break; + default: + break; + } + } +} + +static void ifx_i2c_pal_poll_callback(void *p_ctx) +{ + ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t *)p_ctx; + if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_WRITE) + { + LOG_PL("[IFX-PL]: Poll Timer elapsed -> Restart TX\n"); + //lint --e{534} suppress "Return value is not required to be checked" + pal_i2c_write(p_local_ctx->p_pal_i2c_ctx, p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_tx_len); + } + else if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_READ) + { + LOG_PL("[IFX-PL]: Poll Timer elapsed -> Restart Read Register -> Start TX\n"); + //lint --e{534} suppress "Return value is not required to be checked" + pal_i2c_read(p_local_ctx->p_pal_i2c_ctx,p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_rx_len); + } +} + + +static void ifx_i2c_pl_guard_time_callback(void *p_ctx) +{ + ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t*)p_ctx; + if (p_local_ctx->pl.register_action == PL_ACTION_READ_REGISTER) + { + if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_WRITE) + { + LOG_PL("[IFX-PL]: GT done-> Start RX\n"); + p_local_ctx->pl.i2c_cmd = PL_I2C_CMD_READ; + //lint --e{534} suppress "Return value is not required to be checked" + pal_i2c_read(p_local_ctx->p_pal_i2c_ctx,p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_rx_len); + } + else if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_READ) + { + LOG_PL("[IFX-PL]: GT done -> REG is read\n"); + ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_STACK_SUCCESS); + } + } + else if (p_local_ctx->pl.register_action == PL_ACTION_WRITE_REGISTER) + { + LOG_PL("[IFX-PL]: GT done -> REG written\n"); + ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_STACK_SUCCESS); + } +} + +static void ifx_i2c_pl_pal_event_handler(void *p_ctx, host_lib_status_t event) +{ + ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t*)p_ctx; + switch (event) + { + case PAL_I2C_EVENT_ERROR: + case PAL_I2C_EVENT_BUSY: + // Error event usually occurs when the device is in sleep mode and needs time to wake up + if (p_local_ctx->pl.retry_counter--) + { + LOG_PL("[IFX-PL]: PAL Error -> Continue polling\n"); + pal_os_event_register_callback_oneshot(ifx_i2c_pal_poll_callback,p_local_ctx,PL_POLLING_INVERVAL_US); + } + else + { + LOG_PL("[IFX-PL]: PAL Error -> Stop\n"); + ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_FATAL_ERROR); + } + break; + + case PAL_I2C_EVENT_SUCCESS: + LOG_PL("[IFX-PL]: PAL Success -> Wait Guard Time\n"); + pal_os_event_register_callback_oneshot(ifx_i2c_pl_guard_time_callback,p_local_ctx,PL_GUARD_TIME_INTERVAL_US); + break; + default: + break; + } +} + + +static void ifx_i2c_pl_soft_reset(ifx_i2c_context_t *p_ctx) +{ + uint8_t i2c_mode_value[2] = {0}; + switch(p_ctx->pl.request_soft_reset) + { + case PL_INIT_GET_STATUS_REG: + p_ctx->pl.request_soft_reset = PL_RESET_WRITE; + //Read the status register to check if soft reset is supported + ifx_i2c_pl_read_register(p_ctx, PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE); + break; + + case PL_RESET_WRITE: + //Mask for soft reset bit(5th bit) from the 1st byte of status register + p_ctx->pl.buffer[0] &= PL_REG_I2C_STATE_SOFT_RESET; + if(p_ctx->pl.buffer[0] == PL_REG_I2C_STATE_SOFT_RESET) + { + p_ctx->pl.request_soft_reset = PL_RESET_STARTUP; + //Write 88 register with 0 value + ifx_i2c_pl_write_register(p_ctx, PL_REG_SOFT_RESET, PL_REG_LEN_SOFT_RESET, i2c_mode_value); + } + else + { + //Soft reset is not supported by the slave + p_ctx->pl.frame_state = PL_STATE_UNINIT; + ifx_i2c_pl_frame_event_handler(p_ctx, IFX_I2C_STACK_ERROR); + } + break; + + case PL_RESET_STARTUP: + p_ctx->pl.request_soft_reset= PL_RESET_INIT; + pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_pl_soft_reset, (void *)p_ctx, STARTUP_TIME_MSEC); + break; + + case PL_RESET_INIT: + p_ctx->pl.frame_state = PL_STATE_INIT; + ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); + break; + + default: + break; + } +} + +//lint --e{715} suppress "This is used for synchromous implementation, hence p_ctx not used" +//lint --e{818} suppress "This is ignored as upper layer handler function prototype requires this argument" +static void ifx_i2c_pl_pal_slave_addr_event_handler(void *p_ctx, host_lib_status_t event) +{ + pal_event_status = event; +} + |