mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-28 23:49:44 +08:00
381 lines
12 KiB
C
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
|