/*
 * Copyright 2020-2025 Yuntu Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*!
 * @file ipc_hw_access.h
 * @version 1.4.1
 *
 * @brief IPC Hardware Access — Inter-Peripheral Crossbar clock control register interface.
 *
 * This header provides low-level inline functions for controlling peripheral
 * clock gates, clock sources, and dividers through the IPC (Inter-Peripheral
 * Crossbar) peripheral clock control registers.
 *
 * Functions are organized into:
 *   - **Clock Configuration** — Set peripheral clock source, divider, and gate.
 *   - **Module Reset** — Assert/de-assert software reset for a peripheral.
 *   - **Clock Gate Control** — Enable/disable individual peripheral clocks.
 *   - **Clock Status Query** — Read back clock gate, source, and divider settings.
 */

#ifndef IPC_HW_ACCESS_H
#define IPC_HW_ACCESS_H

#include "device_registers.h"

/*! @brief Clock name mappings
 *         Constant array storing the mappings between clock names and peripheral clock control indexes.
 *         If there is no peripheral clock control index for a clock name, then the corresponding value is
 *         IPC_INVALID_INDEX.
 */
extern const uint16_t clockNameMappings[CLOCK_NAME_COUNT];

#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/

/*******************************************************************************
 * Clock Configuration
 ******************************************************************************/
/*!
 * @name Clock Configuration
 * @brief Set peripheral clock source, divider, and gate in one operation.
 * @{
 */

/*!
 * @brief Configure a peripheral clock control register.
 *
 * Sets the clock source, divider, and gate enable for a peripheral in a
 * single register write.
 *
 * @param[in] ipcCtrlReg  Pointer to the IPC control register for the peripheral.
 * @param[in] clockGate   true to enable the peripheral clock, false to disable.
 * @param[in] clkSrc      Clock source selector value.
 * @param[in] divider     Clock divider value.
 */
static inline void IPC_SetPeripheralClockControl(volatile uint32_t *ipcCtrlReg, bool clockGate, uint32_t clkSrc, uint32_t divider)
{
   /* Configure the peripheral clock source, the fractional clock divider and the clock gate */
   uint32_t value =  IPC_CTRL_SRCSEL(clkSrc)              |
                     IPC_CTRL_DIV(divider)                  |
                     IPC_CTRL_CLKEN(clockGate ? 1U : 0U);

   *ipcCtrlReg = value;
}

/*! @} */ /* End of Clock Configuration */

/*******************************************************************************
 * Module Reset
 ******************************************************************************/
/*!
 * @name Module Reset
 * @brief Assert and de-assert software reset for a peripheral via IPC.
 * @{
 */

/*!
 * @brief Reset a peripheral module via its IPC control register.
 *
 * Asserts and then immediately de-asserts the software reset bit (SWREN)
 * for the peripheral associated with the given control register.
 *
 * @param[in] ctrlReg  Pointer to the IPC control register for the peripheral.
 */
static inline void IPC_ResetModule(volatile uint32_t* ctrlReg)
{
    /* Assert reset */
    *ctrlReg |= IPC_CTRL_SWREN(1UL);
    /* De-assert reset */
    *ctrlReg &= (uint32_t)(~(IPC_CTRL_SWREN_MASK));
}

/*! @} */ /* End of Module Reset */

/*******************************************************************************
 * Clock Gate Control
 ******************************************************************************/
/*!
 * @name Clock Gate Control
 * @brief Enable or disable individual peripheral clocks.
 * @{
 */

/*!
 * @brief Enable or disable the clock for a peripheral.
 *
 * @param[in] ctrlReg        Pointer to the IPC control register for the peripheral.
 * @param[in] isClockEnabled true to enable the clock, false to disable.
 */
static inline void IPC_SetClockMode(volatile uint32_t* ctrlReg,
                                       const bool isClockEnabled)
{
   if (isClockEnabled)
   {
       *ctrlReg |= IPC_CTRL_CLKEN(1UL);
   }
   else
   {
       *ctrlReg &= (uint32_t)(~(IPC_CTRL_CLKEN_MASK));
   }
}

/*! @} */ /* End of Clock Gate Control */

/*******************************************************************************
 * Clock Status Query
 ******************************************************************************/
/*!
 * @name Clock Status Query
 * @brief Read back clock gate state, source selection, and divider value.
 * @{
 */

/*!
 * @brief Get the clock gate state for a peripheral.
 *
 * @param[in] base       IPC base pointer.
 * @param[in] clockName  Peripheral clock name (from clock_names_t).
 * @return true if the peripheral clock is enabled, false if disabled.
 */
static inline bool IPC_GetClockMode(const IPC_Type* const base,
                                       const clock_names_t clockName)
{
   uint32_t regValue = (uint32_t)base->CTRL[clockNameMappings[clockName]];
   regValue = (regValue & IPC_CTRL_CLKEN_MASK) >> IPC_CTRL_CLKEN_SHIFT;
   return (regValue == 0U) ? false : true;
}

/*!
 * @brief Get the clock source selection for a peripheral.
 *
 * @param[in] base       IPC base pointer.
 * @param[in] clockName  Peripheral clock name (from clock_names_t).
 * @return Clock source selector value.
 */
static inline uint32_t IPC_GetClockSourceSel(const IPC_Type* const base,
                                                                 const clock_names_t clockName)
{
   return ((base->CTRL[clockNameMappings[clockName]] & IPC_CTRL_SRCSEL_MASK) >> IPC_CTRL_SRCSEL_SHIFT);
}

/*!
 * @brief Get the clock divider value for a peripheral.
 *
 * @param[in] base       IPC base pointer.
 * @param[in] clockName  Peripheral clock name (from clock_names_t).
 * @return Divider selector value.
 */
static inline uint32_t IPC_GetDividerSel(const IPC_Type* const base,
                                             const clock_names_t clockName)
{
   return ((base->CTRL[clockNameMappings[clockName]] & IPC_CTRL_DIV_MASK) >> IPC_CTRL_DIV_SHIFT);
}

/*! @} */ /* End of Clock Status Query */

#if defined(__cplusplus)
}
#endif /* __cplusplus*/

#endif /* IPC_HW_ACCESS_H */

/*! @}*/
/*******************************************************************************
 * EOF
 ******************************************************************************/
