2024-06-13 13:43:53 -03:00

381 lines
12 KiB
C

/*
* Copyright 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#include "fsl_lpflexcomm.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.lpflexcomm"
#endif
/*!
* @brief Used for conversion between `void*` and `uint32_t`.
*/
typedef union pvoid_to_u32
{
void *pvoid;
uint32_t u32;
} pvoid_to_u32_t;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*! @brief check whether lpflexcomm supports peripheral type */
static bool LP_FLEXCOMM_PeripheralIsPresent(LP_FLEXCOMM_Type *base, LP_FLEXCOMM_PERIPH_T periph);
/*! @brief Changes LP_FLEXCOMM mode. */
static status_t LP_FLEXCOMM_SetPeriph(uint32_t instance, LP_FLEXCOMM_PERIPH_T periph, int lock);
/*! @brief Common LPFLEXCOMM IRQhandle. */
static void LP_FLEXCOMM_CommonIRQHandler(uint32_t instance);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Array to map LP_FLEXCOMM instance number to base address. */
static const uint32_t s_lpflexcommBaseAddrs[] = LP_FLEXCOMM_BASE_ADDRS;
/*! @brief Array to map LP_FLEXCOMM instance PTRS. */
static LP_FLEXCOMM_Type *const s_lpflexcommBase[] = LP_FLEXCOMM_BASE_PTRS;
/*! @brief Pointers to real IRQ handlers installed by drivers for each instance. */
static lpflexcomm_irq_handler_t s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPI2C + 1][ARRAY_SIZE(s_lpflexcommBaseAddrs)];
/*! @brief Pointers to handles for each instance to provide context to interrupt routines */
static void *s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPI2C + 1][ARRAY_SIZE(s_lpflexcommBaseAddrs)];
/*! @brief Array to map LP_FLEXCOMM instance number to IRQ number. */
IRQn_Type const kFlexcommIrqs[] = LP_FLEXCOMM_IRQS;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief IDs of clock for each LP_FLEXCOMM module */
static const clock_ip_name_t s_lpflexcommClocks[] = LP_FLEXCOMM_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET)
/*! @brief Pointers to LP_FLEXCOMM resets for each instance. */
static const reset_ip_name_t s_lpflexcommResets[] = LP_FLEXCOMM_RSTS;
#endif
/*******************************************************************************
* Code
******************************************************************************/
/* check whether lpflexcomm supports peripheral type */
static bool LP_FLEXCOMM_PeripheralIsPresent(LP_FLEXCOMM_Type *base, LP_FLEXCOMM_PERIPH_T periph)
{
if (periph == LP_FLEXCOMM_PERIPH_NONE)
{
return true;
}
else if (periph <= LP_FLEXCOMM_PERIPH_LPI2C)
{
return (base->PSELID & (1UL << ((uint32_t)periph + 3U))) > 0UL ? true : false;
}
else if (periph == LP_FLEXCOMM_PERIPH_LPI2CAndLPUART)
{
return true;
}
else
{
return false;
}
}
/*! @brief Returns for LP_FLEXCOMM base address. */
uint32_t LP_FLEXCOMM_GetBaseAddress(uint32_t instance)
{
if(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBaseAddrs))
{
return s_lpflexcommBaseAddrs[instance];
}
return 0U;
}
/*! brief Returns for LP_FLEXCOMM interrupt source,see #_lpflexcomm_interrupt_flag. */
uint32_t LP_FLEXCOMM_GetInterruptStatus(uint32_t instance)
{
LP_FLEXCOMM_Type *base = s_lpflexcommBase[instance];
return base->ISTAT;
}
/* Get the index corresponding to the LP_FLEXCOMM */
/*! brief Returns instance number for LP_FLEXCOMM module with given base address. */
uint32_t LP_FLEXCOMM_GetInstance(void *base)
{
uint32_t i;
pvoid_to_u32_t BaseAddr;
BaseAddr.pvoid = base;
for (i = 0U; i < (uint32_t)ARRAY_SIZE(s_lpflexcommBaseAddrs); i++)
{
if (BaseAddr.u32 == s_lpflexcommBaseAddrs[i])
{
break;
}
}
assert(i < (uint32_t)ARRAY_SIZE(s_lpflexcommBaseAddrs));
return i;
}
/* Changes LP_FLEXCOMM mode */
static status_t LP_FLEXCOMM_SetPeriph(uint32_t instance, LP_FLEXCOMM_PERIPH_T periph, int lock)
{
assert(periph <= LP_FLEXCOMM_PERIPH_LPI2CAndLPUART);
LP_FLEXCOMM_Type *base = s_lpflexcommBase[instance];
/* Check whether peripheral type is present */
if (!LP_FLEXCOMM_PeripheralIsPresent(base, periph))
{
return kStatus_OutOfRange;
}
/* Flexcomm is locked to different peripheral type than expected */
if (((base->PSELID & LP_FLEXCOMM_PSELID_LOCK_MASK) != 0U) &&
((base->PSELID & LP_FLEXCOMM_PSELID_PERSEL_MASK) != (uint32_t)periph))
{
return kStatus_Fail;
}
/* Check if we are asked to lock */
if (lock != 0)
{
base->PSELID = (uint32_t)periph | LP_FLEXCOMM_PSELID_LOCK_MASK;
}
else
{
base->PSELID = (uint32_t)periph;
}
return kStatus_Success;
}
/*! brief Initializes LP_FLEXCOMM and selects peripheral mode according to the second parameter. */
status_t LP_FLEXCOMM_Init(uint32_t instance, LP_FLEXCOMM_PERIPH_T periph)
{
assert(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBase));
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable the peripheral clock */
CLOCK_EnableClock(s_lpflexcommClocks[instance]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET)
/* Reset the LP_FLEXCOMM module before configuring it.*/
RESET_ClearPeripheralReset(s_lpflexcommResets[instance]);
#endif
/* Set the LP_FLEXCOMM to given peripheral */
return LP_FLEXCOMM_SetPeriph(instance, periph, 0);
}
/*! brief Deinitializes LP_FLEXCOMM. */
void LP_FLEXCOMM_Deinit(uint32_t instance)
{
assert(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBase));
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Disable the peripheral clock */
CLOCK_DisableClock(s_lpflexcommClocks[instance]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
RESET_SetPeripheralReset(s_lpflexcommResets[instance]);
}
/*! brief Sets IRQ handler for given LP_FLEXCOMM module. It is used by drivers register IRQ handler according to
* LP_FLEXCOMM mode */
void LP_FLEXCOMM_SetIRQHandler(uint32_t instance,
lpflexcomm_irq_handler_t handler,
void *lpflexcommHandle,
LP_FLEXCOMM_PERIPH_T periph)
{
assert(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBase));
/* Clear handler first to avoid execution of the handler with wrong handle */
s_lpflexcommIrqHandler[periph][instance] = NULL;
s_lpflexcommHandle[periph][instance] = lpflexcommHandle;
s_lpflexcommIrqHandler[periph][instance] = handler;
}
static void LP_FLEXCOMM_CommonIRQHandler(uint32_t instance)
{
uint32_t interruptStat;
interruptStat = LP_FLEXCOMM_GetInterruptStatus(instance);
if ((interruptStat &
((uint32_t)kLPFLEXCOMM_I2cSlaveInterruptFlag | (uint32_t)kLPFLEXCOMM_I2cMasterInterruptFlag)) != 0U)
{
if (s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPI2C][instance] != NULL)
{
s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPI2C][instance](
instance, s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPI2C][instance]);
}
}
if ((interruptStat & ((uint32_t)kLPFLEXCOMM_UartRxInterruptFlag | (uint32_t)kLPFLEXCOMM_UartTxInterruptFlag)) != 0U)
{
if (s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPUART][instance] != NULL)
{
s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPUART][instance](
instance, s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPUART][instance]);
}
}
if (((interruptStat & (uint32_t)kLPFLEXCOMM_SpiInterruptFlag)) != 0U)
{
if (s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPSPI][instance] != NULL)
{
s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPSPI][instance](
instance, s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPSPI][instance]);
}
}
SDK_ISR_EXIT_BARRIER;
}
/* IRQ handler functions overloading weak symbols in the startup */
#if defined(LP_FLEXCOMM0)
void LP_FLEXCOMM0_DriverIRQHandler(void);
void LP_FLEXCOMM0_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(0U);
}
#endif
#if defined(LP_FLEXCOMM1)
void LP_FLEXCOMM1_DriverIRQHandler(void);
void LP_FLEXCOMM1_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(1U);
}
#endif
#if defined(LP_FLEXCOMM2)
void LP_FLEXCOMM2_DriverIRQHandler(void);
void LP_FLEXCOMM2_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(2U);
}
#endif
#if defined(LP_FLEXCOMM3)
void LP_FLEXCOMM3_DriverIRQHandler(void);
void LP_FLEXCOMM3_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(3U);
}
#endif
#if defined(LP_FLEXCOMM4)
void LP_FLEXCOMM4_DriverIRQHandler(void);
void LP_FLEXCOMM4_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(4U);
}
#endif
#if defined(LP_FLEXCOMM5)
void LP_FLEXCOMM5_DriverIRQHandler(void);
void LP_FLEXCOMM5_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(5U);
}
#endif
#if defined(LP_FLEXCOMM6)
void LP_FLEXCOMM6_DriverIRQHandler(void);
void LP_FLEXCOMM6_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(6U);
}
#endif
#if defined(LP_FLEXCOMM7)
void LP_FLEXCOMM7_DriverIRQHandler(void);
void LP_FLEXCOMM7_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(7U);
}
#endif
#if defined(LP_FLEXCOMM8)
void LP_FLEXCOMM8_DriverIRQHandler(void);
void LP_FLEXCOMM8_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(8U);
}
#endif
#if defined(LP_FLEXCOMM9)
void LP_FLEXCOMM9_DriverIRQHandler(void);
void LP_FLEXCOMM9_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(9U);
}
#endif
#if defined(LP_FLEXCOMM10)
void LP_FLEXCOMM10_DriverIRQHandler(void);
void LP_FLEXCOMM10_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(10U);
}
#endif
#if defined(LP_FLEXCOMM11)
void LP_FLEXCOMM11_DriverIRQHandler(void);
void LP_FLEXCOMM11_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(11U);
}
#endif
#if defined(LP_FLEXCOMM12)
void LP_FLEXCOMM12_DriverIRQHandler(void);
void LP_FLEXCOMM12_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(12U);
}
#endif
#if defined(LP_FLEXCOMM13)
void LP_FLEXCOMM13_DriverIRQHandler(void);
void LP_FLEXCOMM13_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(13U);
}
#endif
#if defined(LP_FLEXCOMM17)
void LP_FLEXCOMM17_DriverIRQHandler(void);
void LP_FLEXCOMM17_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(17U);
}
#endif
#if defined(LP_FLEXCOMM18)
void LP_FLEXCOMM18_DriverIRQHandler(void);
void LP_FLEXCOMM18_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(18U);
}
#endif
#if defined(LP_FLEXCOMM19)
void LP_FLEXCOMM19_DriverIRQHandler(void);
void LP_FLEXCOMM19_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(19U);
}
#endif
#if defined(LP_FLEXCOMM20)
void LP_FLEXCOMM20_DriverIRQHandler(void);
void LP_FLEXCOMM20_DriverIRQHandler(void)
{
LP_FLEXCOMM_CommonIRQHandler(20U);
}
#endif