/**
 * @file xmc_posif.c
 * @date 2019-12-16
 *
 * @cond
 *****************************************************************************
 * XMClib v2.2.0 - XMC Peripheral Driver Library
 *
 * Copyright (c) 2015-2020, Infineon Technologies AG
 * All rights reserved.
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * To improve the quality of the software, users are encouraged to share
 * modifications, enhancements or bug fixes with Infineon Technologies AG
 * at XMCSupport@infineon.com.
 *****************************************************************************
 *
 * Change History
 * --------------
 *
 * 2015-02-18:
 *     - Initial version
 *
 * 2015-02-20:
 *     - Driver description added <BR>
 *
 * 2015-04-30:
 *     - XMC_POSIF_Enable and XMC_POSIF_Disable APIs updated for POSIF1 peripheral check <BR>
 *
 * 2015-06-19:
 *     - Removed GetDriverVersion API <BR>
 *
 * 2017-02-25:
 *     - XMC_POSIF_Enable() and XMC_POSIF_Disable() fixed compilation warnings
 *
 * 2019-12-16:
 *     - Fix including files following the convention: angle brackets are used for standard includes and double quotes for everything else.
 *
 * @endcond
 *
 */

/*********************************************************************************************************************
 * HEADER FILES
 ********************************************************************************************************************/
#include "xmc_posif.h"

/* POSIF is not available on XMC1100 and XMC1200 */
#if defined(POSIF0)
#include "xmc_scu.h"

/*********************************************************************************************************************
 * MACROS
 ********************************************************************************************************************/
#define XMC_POSIF_PCONF_INSEL_Msk        (0x3fUL << POSIF_PCONF_INSEL0_Pos) /*< Mask for input pins selection */
#define XMC_POSIF_INSEL_MAX              (4U) /*< Maximum possible input selector */

/*********************************************************************************************************************
 * LOCAL ROUTINES
 ********************************************************************************************************************/
#ifdef XMC_ASSERT_ENABLE
__STATIC_INLINE bool XMC_POSIF_IsPeripheralValid(const XMC_POSIF_t *const peripheral)
{
  bool tmp;

  tmp = (peripheral == POSIF0);
#if defined(POSIF1)
  tmp |= (peripheral == POSIF1);
#endif

  return tmp;
}
#endif
/*********************************************************************************************************************
 * API IMPLEMENTATION
 ********************************************************************************************************************/

/* API to enable the POSIF module */
void XMC_POSIF_Enable(XMC_POSIF_t *const peripheral)
{
#if UC_FAMILY == XMC4
  XMC_SCU_CLOCK_EnableClock(XMC_SCU_CLOCK_CCU);
#endif

  if (peripheral == POSIF0)
  {
#if defined(CLOCK_GATING_SUPPORTED)
    XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_POSIF0);
#endif
#if defined(PERIPHERAL_RESET_SUPPORTED)
    XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_POSIF0);
#endif
  }
#if defined(POSIF1)
  else if (peripheral == POSIF1)
  {
#if defined(CLOCK_GATING_SUPPORTED)
    XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_POSIF1);
#endif
#if defined(PERIPHERAL_RESET_SUPPORTED)
    XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_POSIF1);
#endif
  }
#endif
  else
  {
    XMC_ASSERT("XMC_POSIF_Disable:Invalid module pointer", 0);
  }
}

/* API to disable the POSIF module */
void XMC_POSIF_Disable(XMC_POSIF_t *const peripheral)
{
  if (peripheral == POSIF0)
  {
#if defined(PERIPHERAL_RESET_SUPPORTED)
    XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_POSIF0);
#endif
#if defined(CLOCK_GATING_SUPPORTED)
    XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_POSIF0);
#endif
  }
#if defined(POSIF1)
  else if (peripheral == POSIF1)
  {
#if defined(PERIPHERAL_RESET_SUPPORTED)
    XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_POSIF1);
#endif
#if defined(CLOCK_GATING_SUPPORTED)
    XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_POSIF1);
#endif
  }
#endif
  else
  {
    XMC_ASSERT("XMC_POSIF_Disable:Invalid module pointer", 0);
  }
}

/* API to initialize POSIF global resources */
void XMC_POSIF_Init(XMC_POSIF_t *const peripheral, const XMC_POSIF_CONFIG_t *const config)
{
  XMC_ASSERT("XMC_POSIF_Init:Invalid module pointer", XMC_POSIF_IsPeripheralValid(peripheral));
  XMC_ASSERT("XMC_POSIF_Init:NULL Pointer", (config != (XMC_POSIF_CONFIG_t *)NULL) );

  /* Enable the POSIF module */
  XMC_POSIF_Enable(peripheral);

  /* Stop POSIF */
  XMC_POSIF_Stop(peripheral);

  /* Program the operational mode, input selectors and debounce filter */
  peripheral->PCONF = config->pconf;
}

/* API to initialize hall sensor interface */
XMC_POSIF_STATUS_t XMC_POSIF_HSC_Init(XMC_POSIF_t *const peripheral, const XMC_POSIF_HSC_CONFIG_t *const config)
{
  XMC_POSIF_STATUS_t retval;

  XMC_ASSERT("XMC_POSIF_HSC_Init:Invalid module pointer\n", XMC_POSIF_IsPeripheralValid(peripheral));
  XMC_ASSERT("XMC_POSIF_HSC_Init:NULL Pointer\n", (config != (XMC_POSIF_HSC_CONFIG_t *)NULL) );

  if (XMC_POSIF_MODE_HALL_SENSOR == (XMC_POSIF_MODE_t)((peripheral->PCONF) & (uint32_t)POSIF_PCONF_FSEL_Msk) )
  {
    peripheral->PCONF |= config->hall_config;
    retval = XMC_POSIF_STATUS_OK;
  }
  else
  {
    retval = XMC_POSIF_STATUS_ERROR;
  }
  return retval;
}

/* API to initialize quadrature decoder interface */
XMC_POSIF_STATUS_t XMC_POSIF_QD_Init(XMC_POSIF_t *const peripheral, const XMC_POSIF_QD_CONFIG_t *const config)
{
  uint8_t reg;
  XMC_POSIF_STATUS_t retval;

  XMC_ASSERT("XMC_POSIF_QD_Init:Invalid module pointer", XMC_POSIF_IsPeripheralValid(peripheral));
  XMC_ASSERT("XMC_POSIF_QD_Init:NULL Pointer", (config != (XMC_POSIF_QD_CONFIG_t *)NULL) );

  reg = (uint8_t)((peripheral->PCONF) & (uint32_t)POSIF_PCONF_FSEL_Msk);
  if (((uint32_t)XMC_POSIF_MODE_QD == reg) || ((uint32_t)XMC_POSIF_MODE_MCM_QD == reg))
  {
    /* Program the quadrature mode */
    peripheral->PCONF |= (uint32_t)(config->mode) << POSIF_PCONF_QDCM_Pos;
    peripheral->QDC = config->qdc;
    retval = XMC_POSIF_STATUS_OK;
  }
  else
  {
    retval = XMC_POSIF_STATUS_ERROR;
  }

  return retval;
}

/* API to initialize multi-channel mode.
 * This is used in Hall mode, standalone multi-channel mode and quadrature with multi-channel mode
 */
XMC_POSIF_STATUS_t XMC_POSIF_MCM_Init(XMC_POSIF_t *const peripheral, const XMC_POSIF_MCM_CONFIG_t *const config)
{
  XMC_POSIF_STATUS_t retval;

  XMC_ASSERT("XMC_POSIF_MCM_Init:Invalid module pointer", XMC_POSIF_IsPeripheralValid(peripheral));
  XMC_ASSERT("XMC_POSIF_MCM_Init:NULL Pointer", (config != (XMC_POSIF_MCM_CONFIG_t *)NULL) );

  if ((XMC_POSIF_MODE_t)((peripheral->PCONF) & (uint32_t)POSIF_PCONF_FSEL_Msk) != XMC_POSIF_MODE_QD)
  {
    peripheral->PCONF |= config->mcm_config;
    retval = XMC_POSIF_STATUS_OK;
  }
  else
  {
    retval = XMC_POSIF_STATUS_ERROR;
  }
  return retval;
}

/* API to configure input source */
void XMC_POSIF_SelectInputSource (XMC_POSIF_t *const peripheral, const XMC_POSIF_INPUT_PORT_t input0,
                                  const XMC_POSIF_INPUT_PORT_t input1, const XMC_POSIF_INPUT_PORT_t input2)
{
  uint32_t reg;
  XMC_ASSERT("XMC_POSIF_SelectInputSource:Invalid module pointer", XMC_POSIF_IsPeripheralValid(peripheral));
  XMC_ASSERT("XMC_POSIF_SelectInputSource:Wrong input port input0", (input0 < XMC_POSIF_INSEL_MAX));
  XMC_ASSERT("XMC_POSIF_SelectInputSource:Wrong input port input1", (input1 < XMC_POSIF_INSEL_MAX));
  XMC_ASSERT("XMC_POSIF_SelectInputSource:Wrong input port input2", (input2 < XMC_POSIF_INSEL_MAX));

  reg = (uint32_t)((((uint32_t)input0 << POSIF_PCONF_INSEL0_Pos) & (uint32_t)POSIF_PCONF_INSEL0_Msk) |
                   (((uint32_t)input1 << POSIF_PCONF_INSEL1_Pos) & (uint32_t)POSIF_PCONF_INSEL1_Msk) |
                   (((uint32_t)input2 << POSIF_PCONF_INSEL2_Pos) & (uint32_t)POSIF_PCONF_INSEL2_Msk));
  peripheral->PCONF = ((peripheral->PCONF & ~(uint32_t)XMC_POSIF_PCONF_INSEL_Msk) | reg);
}

/* API to select an interrupt node */
void XMC_POSIF_SetInterruptNode(XMC_POSIF_t *const peripheral, const XMC_POSIF_IRQ_EVENT_t event, const XMC_POSIF_SR_ID_t sr)
{
  uint32_t reg;

  XMC_ASSERT("XMC_POSIF_SetInterruptNode:Invalid module pointer", XMC_POSIF_IsPeripheralValid(peripheral));
  XMC_ASSERT("XMC_POSIF_SetInterruptNode:Wrong IRQ event", (event <= XMC_POSIF_IRQ_EVENT_PCLK) );
  XMC_ASSERT("XMC_POSIF_SetInterruptNode:Wrong SR ID", (sr <= XMC_POSIF_SR_ID_1) );

  reg = peripheral->PFLGE;
  reg &= ~((uint32_t)1 << ((uint32_t)event + (uint32_t)POSIF_PFLGE_CHESEL_Pos));
  reg |= (uint32_t)sr << ((uint32_t)event + (uint32_t)POSIF_PFLGE_CHESEL_Pos);
  peripheral->PFLGE = reg;
}
#endif /* #if defined(POSIF0) */
