/* | |
* Copyright (c) 2016, Freescale Semiconductor, Inc. | |
* Copyright 2016-2017 NXP | |
* All rights reserved. | |
* | |
* SPDX-License-Identifier: BSD-3-Clause | |
*/ | |
#include "fsl_common.h" | |
#include "fsl_flexcomm.h" | |
/******************************************************************************* | |
* Definitions | |
******************************************************************************/ | |
/* Component ID definition, used by tools. */ | |
#ifndef FSL_COMPONENT_ID | |
#define FSL_COMPONENT_ID "platform.drivers.flexcomm" | |
#endif | |
/******************************************************************************* | |
* Prototypes | |
******************************************************************************/ | |
/*! @brief Set the FLEXCOMM mode . */ | |
static status_t FLEXCOMM_SetPeriph(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph, int lock); | |
/*! @brief check whether flexcomm supports peripheral type */ | |
static bool FLEXCOMM_PeripheralIsPresent(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph); | |
/******************************************************************************* | |
* Variables | |
******************************************************************************/ | |
/*! @brief Pointers to real IRQ handlers installed by drivers for each instance. */ | |
static flexcomm_irq_handler_t s_flexcommIrqHandler[FSL_FEATURE_SOC_FLEXCOMM_COUNT]; | |
/*! @brief Pointers to handles for each instance to provide context to interrupt routines */ | |
static void *s_flexcommHandle[FSL_FEATURE_SOC_FLEXCOMM_COUNT]; | |
/*! @brief Array to map FLEXCOMM instance number to IRQ number. */ | |
IRQn_Type const kFlexcommIrqs[] = FLEXCOMM_IRQS; | |
/*! @brief Array to map FLEXCOMM instance number to base address. */ | |
static const uint32_t s_flexcommBaseAddrs[FSL_FEATURE_SOC_FLEXCOMM_COUNT] = FLEXCOMM_BASE_ADDRS; | |
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) | |
/*! @brief IDs of clock for each FLEXCOMM module */ | |
static const clock_ip_name_t s_flexcommClocks[] = FLEXCOMM_CLOCKS; | |
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ | |
#if !(defined(FSL_FEATURE_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_FLEXCOMM_HAS_NO_RESET) | |
/*! @brief Pointers to FLEXCOMM resets for each instance. */ | |
static const reset_ip_name_t s_flexcommResets[] = FLEXCOMM_RSTS; | |
#endif | |
/******************************************************************************* | |
* Code | |
******************************************************************************/ | |
/* check whether flexcomm supports peripheral type */ | |
static bool FLEXCOMM_PeripheralIsPresent(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph) | |
{ | |
if (periph == FLEXCOMM_PERIPH_NONE) | |
{ | |
return true; | |
} | |
else if (periph <= FLEXCOMM_PERIPH_I2S_TX) | |
{ | |
return (base->PSELID & (uint32_t)(1 << ((uint32_t)periph + 3))) > (uint32_t)0 ? true : false; | |
} | |
else if (periph == FLEXCOMM_PERIPH_I2S_RX) | |
{ | |
return (base->PSELID & (1 << 7)) > (uint32_t)0 ? true : false; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/* Get the index corresponding to the FLEXCOMM */ | |
/*! brief Returns instance number for FLEXCOMM module with given base address. */ | |
uint32_t FLEXCOMM_GetInstance(void *base) | |
{ | |
int i; | |
for (i = 0; i < FSL_FEATURE_SOC_FLEXCOMM_COUNT; i++) | |
{ | |
if ((uint32_t)base == s_flexcommBaseAddrs[i]) | |
{ | |
return i; | |
} | |
} | |
assert(false); | |
return 0; | |
} | |
/* Changes FLEXCOMM mode */ | |
static status_t FLEXCOMM_SetPeriph(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph, int lock) | |
{ | |
/* Check whether peripheral type is present */ | |
if (!FLEXCOMM_PeripheralIsPresent(base, periph)) | |
{ | |
return kStatus_OutOfRange; | |
} | |
/* Flexcomm is locked to different peripheral type than expected */ | |
if ((base->PSELID & FLEXCOMM_PSELID_LOCK_MASK) && ((base->PSELID & FLEXCOMM_PSELID_PERSEL_MASK) != periph)) | |
{ | |
return kStatus_Fail; | |
} | |
/* Check if we are asked to lock */ | |
if (lock) | |
{ | |
base->PSELID = (uint32_t)periph | FLEXCOMM_PSELID_LOCK_MASK; | |
} | |
else | |
{ | |
base->PSELID = (uint32_t)periph; | |
} | |
return kStatus_Success; | |
} | |
/*! brief Initializes FLEXCOMM and selects peripheral mode according to the second parameter. */ | |
status_t FLEXCOMM_Init(void *base, FLEXCOMM_PERIPH_T periph) | |
{ | |
int idx = FLEXCOMM_GetInstance(base); | |
if (idx < 0) | |
{ | |
return kStatus_InvalidArgument; | |
} | |
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) | |
/* Enable the peripheral clock */ | |
CLOCK_EnableClock(s_flexcommClocks[idx]); | |
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ | |
#if !(defined(FSL_FEATURE_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_FLEXCOMM_HAS_NO_RESET) | |
/* Reset the FLEXCOMM module */ | |
RESET_PeripheralReset(s_flexcommResets[idx]); | |
#endif | |
/* Set the FLEXCOMM to given peripheral */ | |
return FLEXCOMM_SetPeriph((FLEXCOMM_Type *)base, periph, 0); | |
} | |
/*! brief Sets IRQ handler for given FLEXCOMM module. It is used by drivers register IRQ handler according to FLEXCOMM | |
* mode */ | |
void FLEXCOMM_SetIRQHandler(void *base, flexcomm_irq_handler_t handler, void *handle) | |
{ | |
uint32_t instance; | |
/* Look up instance number */ | |
instance = FLEXCOMM_GetInstance(base); | |
/* Clear handler first to avoid execution of the handler with wrong handle */ | |
s_flexcommIrqHandler[instance] = NULL; | |
s_flexcommHandle[instance] = handle; | |
s_flexcommIrqHandler[instance] = handler; | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
/* IRQ handler functions overloading weak symbols in the startup */ | |
#if defined(FLEXCOMM0) | |
void FLEXCOMM0_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[0]); | |
s_flexcommIrqHandler[0]((void *)s_flexcommBaseAddrs[0], s_flexcommHandle[0]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM1) | |
void FLEXCOMM1_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[1]); | |
s_flexcommIrqHandler[1]((void *)s_flexcommBaseAddrs[1], s_flexcommHandle[1]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM2) | |
void FLEXCOMM2_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[2]); | |
s_flexcommIrqHandler[2]((void *)s_flexcommBaseAddrs[2], s_flexcommHandle[2]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM3) | |
void FLEXCOMM3_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[3]); | |
s_flexcommIrqHandler[3]((void *)s_flexcommBaseAddrs[3], s_flexcommHandle[3]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM4) | |
void FLEXCOMM4_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[4]); | |
s_flexcommIrqHandler[4]((void *)s_flexcommBaseAddrs[4], s_flexcommHandle[4]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM5) | |
void FLEXCOMM5_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[5]); | |
s_flexcommIrqHandler[5]((void *)s_flexcommBaseAddrs[5], s_flexcommHandle[5]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM6) | |
void FLEXCOMM6_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[6]); | |
s_flexcommIrqHandler[6]((void *)s_flexcommBaseAddrs[6], s_flexcommHandle[6]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM7) | |
void FLEXCOMM7_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[7]); | |
s_flexcommIrqHandler[7]((void *)s_flexcommBaseAddrs[7], s_flexcommHandle[7]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM8) | |
void FLEXCOMM8_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[8]); | |
s_flexcommIrqHandler[8]((void *)s_flexcommBaseAddrs[8], s_flexcommHandle[8]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM9) | |
void FLEXCOMM9_DriverIRQHandler(void) | |
{ | |
assert(s_flexcommIrqHandler[9]); | |
s_flexcommIrqHandler[9]((void *)s_flexcommBaseAddrs[9], s_flexcommHandle[9]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM14) | |
void FLEXCOMM14_DriverIRQHandler(void) | |
{ | |
uint32_t instance; | |
/* Look up instance number */ | |
instance = FLEXCOMM_GetInstance(FLEXCOMM14); | |
assert(s_flexcommIrqHandler[instance]); | |
s_flexcommIrqHandler[instance]((void *)s_flexcommBaseAddrs[instance], s_flexcommHandle[instance]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif | |
#if defined(FLEXCOMM15) | |
void FLEXCOMM15_DriverIRQHandler(void) | |
{ | |
uint32_t instance; | |
/* Look up instance number */ | |
instance = FLEXCOMM_GetInstance(FLEXCOMM14); | |
assert(s_flexcommIrqHandler[instance]); | |
s_flexcommIrqHandler[instance]((void *)s_flexcommBaseAddrs[instance], s_flexcommHandle[instance]); | |
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | |
exception return operation might vector to incorrect interrupt */ | |
#if defined __CORTEX_M && (__CORTEX_M == 4U) | |
__DSB(); | |
#endif | |
} | |
#endif |