diff options
Diffstat (limited to '')
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c new file mode 100644 index 0000000000..1be83f8101 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_smartcard_emvsim.h" +#include "fsl_smartcard_phy.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.smartcard_phy_emvsim" +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Private Functions + ******************************************************************************/ +static uint32_t smartcard_phy_emvsim_InterfaceClockInit(EMVSIM_Type *base, + const smartcard_interface_config_t *config, + uint32_t srcClock_Hz); + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief This function initializes clock module used for card clock generation + */ +static uint32_t smartcard_phy_emvsim_InterfaceClockInit(EMVSIM_Type *base, + const smartcard_interface_config_t *config, + uint32_t srcClock_Hz) +{ + assert((NULL != config) && (0u != srcClock_Hz)); + + uint32_t emvsimClkMhz = 0u; + uint8_t emvsimPRSCValue; + + /* Retrieve EMV SIM clock */ + emvsimClkMhz = srcClock_Hz / 1000000u; + /* Calculate MOD value */ + emvsimPRSCValue = (uint8_t)((emvsimClkMhz * 1000u) / (config->smartCardClock / 1000u)); + /* Set clock prescaler */ + base->CLKCFG = (base->CLKCFG & ~EMVSIM_CLKCFG_CLK_PRSC_MASK) | EMVSIM_CLKCFG_CLK_PRSC(emvsimPRSCValue); + + return config->smartCardClock; +} + +void SMARTCARD_PHY_GetDefaultConfig(smartcard_interface_config_t *config) +{ + assert((NULL != config)); + + /* Initializes the configure structure to zero. */ + (void)memset(config, 0, sizeof(*config)); + + config->clockToResetDelay = SMARTCARD_INIT_DELAY_CLOCK_CYCLES; + config->vcc = kSMARTCARD_VoltageClassB3_3V; +} + +status_t SMARTCARD_PHY_Init(void *base, smartcard_interface_config_t const *config, uint32_t srcClock_Hz) +{ + if ((NULL == config) || (0u == srcClock_Hz)) + { + return kStatus_SMARTCARD_InvalidInput; + } + EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base; + + /* SMARTCARD clock initialization. Clock is still not active after this call */ + (void)smartcard_phy_emvsim_InterfaceClockInit(emvsimBase, config, srcClock_Hz); + + /* Configure EMVSIM direct interface driver interrupt occur according card presence */ + if ((emvsimBase->PCSR & EMVSIM_PCSR_SPDP_MASK) != 0u) + { + emvsimBase->PCSR &= ~EMVSIM_PCSR_SPDES_MASK; + } + else + { + emvsimBase->PCSR |= EMVSIM_PCSR_SPDES_MASK; + } + /* Un-mask presence detect interrupt flag */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SPDIM_MASK; + + return kStatus_SMARTCARD_Success; +} + +void SMARTCARD_PHY_Deinit(void *base, smartcard_interface_config_t const *config) +{ + assert((NULL != config)); + /* Deactivate VCC, CLOCK */ + ((EMVSIM_Type *)base)->PCSR &= ~(EMVSIM_PCSR_SCEN_MASK | EMVSIM_PCSR_SVCC_EN_MASK); +} + +status_t SMARTCARD_PHY_Activate(void *base, smartcard_context_t *context, smartcard_reset_type_t resetType) +{ + if ((NULL == context) || (NULL == context->timeDelay)) + { + return kStatus_SMARTCARD_InvalidInput; + } + assert(context->interfaceConfig.vcc == kSMARTCARD_VoltageClassB3_3V); + + EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base; + + context->timersState.initCharTimerExpired = false; + context->resetType = resetType; + + /* Disable receiver to deactivate GPC timers trigger */ + emvsimBase->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; + if (resetType == kSMARTCARD_ColdReset) + { /* Set polarity of VCC to active high, Enable VCC for SMARTCARD, Enable smart card clock */ + emvsimBase->PCSR = + (emvsimBase->PCSR & ~EMVSIM_PCSR_VCCENP_MASK) | (EMVSIM_PCSR_SVCC_EN_MASK | EMVSIM_PCSR_SCEN_MASK); + /* Set transfer inversion to default(direct) value */ + emvsimBase->CTRL &= ~EMVSIM_CTRL_IC_MASK; + } + else if (resetType == kSMARTCARD_WarmReset) + { /* Ensure that card is already active */ + if (!context->cardParams.active) + { /* Card is not active;hence return */ + return kStatus_SMARTCARD_CardNotActivated; + } + } + else + { + return kStatus_SMARTCARD_InvalidInput; + } + /* Set Reset low */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SRST_MASK; + /* Calculate time delay needed for reset */ + uint32_t temp = + ((((uint32_t)10000u * context->interfaceConfig.clockToResetDelay) / context->interfaceConfig.smartCardClock) * + 100u) + + 1u; + context->timeDelay(temp); + /* Pull reset HIGH Now to mark the end of Activation sequence */ + emvsimBase->PCSR |= EMVSIM_PCSR_SRST_MASK; + /* Disable GPC timers input clock */ + emvsimBase->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK); + /* Down counter trigger, and clear any pending counter status flag */ + emvsimBase->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK | EMVSIM_TX_STATUS_GPCNT0_TO_MASK; + /* Set counter value for TS detection delay */ + emvsimBase->GPCNT0_VAL = (SMARTCARD_INIT_DELAY_CLOCK_CYCLES + SMARTCARD_INIT_DELAY_CLOCK_CYCLES_ADJUSTMENT); + /* Pre-load counter value for ATR duration delay */ + emvsimBase->GPCNT1_VAL = (SMARTCARD_EMV_ATR_DURATION_ETU + SMARTCARD_ATR_DURATION_ADJUSTMENT); + /* Select the clock for GPCNT for both TS detection and early start of ATR duration counter */ + emvsimBase->CLKCFG |= + (EMVSIM_CLKCFG_GPCNT0_CLK_SEL(kEMVSIM_GPCCardClock) | EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCTxClock)); + /* Set receiver to ICM mode, Flush RX FIFO */ + emvsimBase->CTRL |= (EMVSIM_CTRL_ICM_MASK | EMVSIM_CTRL_FLSH_RX_MASK); + /* Enable counter interrupt for TS detection */ + emvsimBase->INT_MASK &= ~EMVSIM_INT_MASK_GPCNT0_IM_MASK; + /* Clear any pending status flags */ + emvsimBase->RX_STATUS = 0xFFFFFFFFu; + /* Enable receiver */ + emvsimBase->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + /* Here the card was activated */ + context->cardParams.active = true; + + return kStatus_SMARTCARD_Success; +} + +status_t SMARTCARD_PHY_Deactivate(void *base, smartcard_context_t *context) +{ + if ((NULL == context)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base; + + /* Assert Reset */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SRST_MASK; + /* Stop SMARTCARD clock generation */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SCEN_MASK; + /* Deactivate card by disabling VCC */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SVCC_EN_MASK; + /* According EMV 4.3 specification deactivation sequence should be done within 100ms. + * The period is measured from the time that RST is set to state L to the time that Vcc + * reaches 0.4 V or less. + */ + context->timeDelay(100 * 1000); + /* Here the card was deactivated */ + context->cardParams.active = false; + + return kStatus_SMARTCARD_Success; +} + +status_t SMARTCARD_PHY_Control(void *base, + smartcard_context_t *context, + smartcard_interface_control_t control, + uint32_t param) +{ + if ((NULL == context)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + status_t status = kStatus_SMARTCARD_Success; + + switch (control) + { + case kSMARTCARD_InterfaceSetVcc: + /* Only 3.3V interface supported by the direct interface */ + assert((smartcard_card_voltage_class_t)param == kSMARTCARD_VoltageClassB3_3V); + context->interfaceConfig.vcc = (smartcard_card_voltage_class_t)param; + break; + case kSMARTCARD_InterfaceSetClockToResetDelay: + /* Set interface clock to Reset delay set by caller */ + context->interfaceConfig.clockToResetDelay = param; + break; + case kSMARTCARD_InterfaceReadStatus: + /* Expecting active low present detect */ + context->cardParams.present = (bool)((emvsim_presence_detect_status_t)(uint32_t)( + (((EMVSIM_Type *)base)->PCSR & EMVSIM_PCSR_SPDP_MASK) >> + EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsLow); + break; + default: + status = kStatus_SMARTCARD_InvalidInput; + break; + } + + return status; +} |