view src/cs/drivers/drv_core/abb/abb.c @ 266:160a5b3a076c

new ABB_SLEEP_RESTRICTION definition in fc-target.h When we first introduced the mechanism to suppress ABB superdeep sleep on targets with LCDs powered from Iota VRIO, we made it conditional on CONFIG_TARGET_LUNA. This conditional is now being generalized: the feature in question is now conditionalized on the new ABB_SLEEP_RESTRICTION preprocessor symbol, to be defined in targets/*.h for those targets that need it. The new ABB_SLEEP_RESTRICTION definition is being added to targets/luna[12].h to keep the actual logic unchanged.
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 02 Jun 2021 02:12:14 +0000
parents 0ed36de51973
children
line wrap: on
line source

/**********************************************************************************/
/*            TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION              */
/*                                                                                */
/*   Property of Texas Instruments -- For  Unrestricted  Internal  Use  Only      */
/*   Unauthorized reproduction and/or distribution is strictly prohibited.  This  */
/*   product  is  protected  under  copyright  law  and  trade  secret law as an  */
/*   unpublished work.  Created 1987, (C) Copyright 1997 Texas Instruments.  All  */
/*   rights reserved.                                                             */
/*                                                                                */
/*                                                                                */
/*   Filename         : abb.c                                                     */
/*                                                                                */
/*   Description      : Functions to drive the ABB device.                        */
/*                      The Serial Port Interface is used to connect the TI       */
/*                      Analog BaseBand (ABB).                                    */
/*                      It is assumed that the ABB is connected as the SPI        */
/*                      device 0.                                                 */
/*                                                                                */
/*   Author           : Pascal PUEL                                               */
/*                                                                                */
/*   Version number   : 1.3                                                       */
/*                                                                                */
/*   Date and time    : 08/22/03                                                       */
/*                                                                                */
/*   Previous delta   : Creation                                                  */
/*                                                                                */
/**********************************************************************************/

#include "l1sw.cfg"

#include "chipset.cfg"
#include "board.cfg"
#include "rf.cfg"
#include "swconfig.cfg"
#include "sys.cfg"
#include "abb.h"
#include "l1_macro.h"
#include "l1_confg.h"
#include "clkm/clkm.h"         // for wait_ARM_cycles function
#include "abb_inline.h"
#include "ulpd/ulpd.h"        // for FRAME_STOP definition
#include "nucleus.h"      // for NUCLEUS functions and types
#include "l1_types.h"

#if (OP_L1_STANDALONE == 0)
  #include "main/sys_types.h"
  #include "rv/general.h"
  #include "buzzer/buzzer.h"	     // for BZ_KeyBeep_OFF function
#else
  #include "sys_types.h"
#endif

#if (VCXO_ALGO == 1)
  #include "l1_ctl.h"
#endif

#if (RF_FAM == 35)
  #include "l1_rf35.h"
#endif

#if (RF_FAM == 12)
  #include "tpudrv12.h"
  #include "l1_rf12.h"
#endif

#if (RF_FAM == 10)
  #include "l1_rf10.h"
#endif

#if (RF_FAM == 8)
  #include "l1_rf8.h"
#endif

#if (RF_FAM == 2)
  #include "l1_rf2.h"
#endif

/*
 * The following conditional compilation control is a FreeCalypso addition.
 * TI's original code always configured the BCICONF register with
 * MESBB and BBCHGEN bits set, enabling both charging and the measurement
 * resistive divider for the backup battery.  However, on our primary
 * hw targets (Openmoko GTA02 and our own FCDEV3B) Iota's VBACKUP pin
 * is unconnected, whereas on Mot C139 and Pirelli DP-L10 "alien" hw
 * the VBACKUP situation is unclear.  But at least on our known hw
 * with VBACKUP unconnected, it is better to leave backup battery charging
 * and measurement OFF - TI's original config seems to be a drain on
 * the main battery.  Therefore, we are going to leave MESBB and BBCHGEN
 * off until and unless we have a hw target where backup battery charging
 * and measurement are appropriate.
 */

#define	ENABLE_BACKUP_BATTERY	0

/*
 * The following ABB_sleep_allowed global variable is yet another FreeCalypso
 * addition.  Here is the issue: some handset boards have the controller/driver
 * chip in the LCD powered from Iota VRIO, which is generally a very sensible
 * arrangement.  As one reference example, our 176x220 pixel TFT LCDs which
 * we are considering for our own FC handset draw about 3 mA from their Vci
 * supply which we connect to VRIO - perfectly fine when the regulators are
 * in their normal Active mode.  But what about sleep mode?  Sleep mode VRIO
 * current limit is only 1 mA, thus the combination of the LCD being on and
 * drawing 3 mA with the ABB in sleep mode is invalid.  TI's original code
 * already had a check for VRPCSTS: PWON and RPWON need to be released and
 * the charger needs to be unplugged in order to enter ABB superdeep sleep.
 * We are extending this check with one more condition: ABB_sleep_allowed
 * needs to be nonzero; the intent is that this variable will be set by the
 * code responsible for putting the LCD into its own powerdown mode.
 * This logic is included only for affected targets with LCDs.
 */

#ifdef ABB_SLEEP_RESTRICTION
int ABB_sleep_allowed = 0;
#endif

#if (ABB_SEMAPHORE_PROTECTION)

static NU_SEMAPHORE abb_sem;

/*-----------------------------------------------------------------------*/
/* ABB_Sem_Create()                                                      */
/*                                                                       */
/* This function creates the Nucleus semaphore to protect ABB accesses   */
/* against preemption.                                                   */
/* No check on the result.                                               */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Sem_Create(void)
{
  // create a semaphore with an initial count of 1 and with FIFO type suspension.
  NU_Create_Semaphore(&abb_sem, "ABB_SEM", 1, NU_FIFO);
}

#endif  // ABB_SEMAPHORE_PROTECTION

/*-----------------------------------------------------------------------*/
/* ABB_Wait_IBIC_Access()                                                */
/*                                                                       */
/* This function waits for the first IBIC access.                        */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Wait_IBIC_Access(void)
{
  #if (ANLG_FAM == 1)
    // Wait 6 OSCAS cycles (100 KHz) for first IBIC access
    // (i.e wait 60us + 10% security marge = 66us)
    wait_ARM_cycles(convert_nanosec_to_cycles(66000));
  #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
    // Wait 6 x 32 KHz clock cycles for first IBIC access
    // (i.e wait 187us + 10% security marge = 210us)
    wait_ARM_cycles(convert_nanosec_to_cycles(210000));
  #endif
}


/*-----------------------------------------------------------------------*/
/* ABB_Write_Register_on_page()                                          */
/*                                                                       */
/* This function manages all the spi serial transfer to write to an      */
/* ABB register on a specified page.                                     */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Write_Register_on_page(SYS_UWORD16 page, SYS_UWORD16 reg_id, SYS_UWORD16 value)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;

  #if ((ABB_SEMAPHORE_PROTECTION == 1) || (ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_WR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  // set the ABB page for register access
  ABB_SetPage(page);

  // Write value in reg_id
  ABB_WriteRegister(reg_id, value);

  // set the ABB page for register access at page 0
  ABB_SetPage(PAGE0);

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if ((ABB_SEMAPHORE_PROTECTION == 1) || (ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION
}


/*-----------------------------------------------------------------------*/
/* ABB_Read_Register_on_page()                                           */
/*                                                                       */
/* This function manages all the spi serial transfer to read one         */
/* ABB register on a specified page.                                     */
/*                                                                       */
/* Returns the real data value of the register.                          */
/*                                                                       */
/*-----------------------------------------------------------------------*/
SYS_UWORD16 ABB_Read_Register_on_page(SYS_UWORD16 page, SYS_UWORD16 reg_id)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;
  SYS_UWORD16 reg_val;

  #if ((ABB_SEMAPHORE_PROTECTION == 1) || (ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for RD and WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_RDWR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  /* set the ABB page for register access */
  ABB_SetPage(page);

  /* Read selected ABB register */
  reg_val = ABB_ReadRegister(reg_id);

  /* set the ABB page for register access at page 0 */
  ABB_SetPage(PAGE0);

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if ((ABB_SEMAPHORE_PROTECTION == 1) || (ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION

  return (reg_val);     // Return result
}

/*------------------------------------------------------------------------*/
/* ABB_free_13M()                                                         */
/*                                                                        */
/* This function sets the 13M clock working in ABB. A wait loop           */
/* is required to allow first slow access to ABB clock register.          */
/*                                                                        */
/* WARNING !! : this function must not be protected by semaphore !!       */
/*                                                                        */
/*------------------------------------------------------------------------*/
void ABB_free_13M(void)
{
  volatile SYS_UWORD16 status;

  // Start spi clock, mask IT for WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_WR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  ABB_SetPage(PAGE0);

  // This transmission frees the CLK13 in ABB.
  ABB_WriteRegister(TOGBR2, 0x08);

  // Wait for first IBIC access
  ABB_Wait_IBIC_Access();

  // SW Workaround : This transmission has to be done twice.
  ABB_WriteRegister(TOGBR2, 0x08);

  // Wait for first IBIC access
  ABB_Wait_IBIC_Access();

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif
}


/*------------------------------------------------------------------------*/
/* ABB_stop_13M()                                                         */
/*                                                                        */
/* This function stops the 13M clock in ABB.                              */
/*                                                                        */
/*------------------------------------------------------------------------*/
void ABB_stop_13M(void)
{
  volatile SYS_UWORD16 status;

  // Start spi clock, mask IT for WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_WR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  ABB_SetPage(PAGE0);

  // Set ACTIVMCLK = 0.
  ABB_WriteRegister(TOGBR2, 0x04);

  // Wait for first IBIC access
  ABB_Wait_IBIC_Access();

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif
}


/*------------------------------------------------------------------------*/
/* ABB_Read_Status()                                                      */
/*                                                                        */
/* This function reads and returns the value of VRPCSTS ABB register.     */
/*                                                                        */
/*------------------------------------------------------------------------*/
SYS_UWORD16 ABB_Read_Status(void)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;
  SYS_UWORD16 reg_val;

  #if ((ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_WR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  ABB_SetPage(PAGE0);

  #if (ANLG_FAM == 1) || (ANLG_FAM == 2)
    ABB_SetPage(PAGE0);
    reg_val = ABB_ReadRegister(VRPCSTS);
  #elif (ANLG_FAM == 3)
    ABB_SetPage(PAGE1);
    reg_val = ABB_ReadRegister(VRPCCFG);
  #endif

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if ((ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION

  return (reg_val);
}

/*------------------------------------------------------------------------*/
/* ABB_on()                                                               */
/*                                                                        */
/* This function configures ABB registers to work in ON condition         */
/*                                                                        */
/*------------------------------------------------------------------------*/
void ABB_on(SYS_UWORD16 modules, SYS_UWORD8 bRecoveryFlag)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;
  #if ((ANLG_FAM == 2) || (ANLG_FAM == 3))
    SYS_UWORD32 reg;
  #endif

  #if (ABB_SEMAPHORE_PROTECTION == 3)

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // a possible cause of the recovery is that ABB is on Oscas => switch from Oscas to CLK13
  if (bRecoveryFlag)
  {
    // RESTITUTE 13MHZ CLOCK TO ABB
    //---------------------------------------------------
    ABB_free_13M();

    // RESTITUTE 13MHZ CLOCK TO ABB AGAIN (C.F. BUG1719)
    //---------------------------------------------------
    ABB_free_13M();
  }

  // Start spi clock, mask IT for RD and WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_RDWR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  ABB_SetPage(PAGE0);

  // This transmission disables MADC,AFC,VDL,VUL modules.
  ABB_WriteRegister(TOGBR1, 0x0155);

  #if (ANLG_FAM == 1)
    // This transmission disables Band gap fast mode Enable BB charge.
    ABB_WriteRegister(VRPCCTL2, 0x1fc);

    /* *********** DC/DC enabling selection ************************************************************** */
    // This transmission changes the register page in OMEGA for usp to pg1.
    ABB_SetPage(PAGE1);

    /* Insert here accesses to modify DC/DC parameters. Default is a switching frequency of 240 Khz */
    {
      SYS_UWORD8 vrpcctrl3_data;

      #if (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11)
        vrpcctrl3_data = 0x007d;  // core voltage 1.4V for C035
      #else
        vrpcctrl3_data = 0x00bd;  // core voltage 1.8V for C05
      #endif

    if(modules & DCDC)    // check if the DCDC is enabled
    {
       vrpcctrl3_data |= 0x0002; // set DCDCEN
    }

    // This access disables the DCDC.
    ABB_WriteRegister(VRPCCTRL3, vrpcctrl3_data);
    }

    /* ************************  SELECTION OF TEST MODE FOR ABB **************************************** */
    /* This test configuration allows visibility on BULENA,BULON,BDLON,BDLENA on test pins               */
    /* ***************************************************************************************************/
    #if (BOARD==6)&& (ANLG_FAM==1)  //BUG01967 to remove access to TAPCTRL   (EVA4 board and Nausica)
      // This transmission enables Omega test register.
      ABB_WriteRegister(TAPCTRL, 0x01);

      // This transmission select Omega test instruction.
      ABB_WriteRegister(TAPREG, TSPTEST1);

      // This transmission disables Omega test register.
      ABB_WriteRegister(TAPCTRL, 0x00);
    #endif
    /* *************************************************************************************************** */

    if (!bRecoveryFlag)    // Check recovery status from L1, prevent G23 SIM issue
    {
      // This transmission changes SIM power supply to 3 volts.
      ABB_WriteRegister(VRPCCTRL1, 0x45);
    }

    ABB_SetPage(PAGE0);

    // This transmission enables selected OMEGA modules.
    ABB_WriteRegister(TOGBR1, (modules & ~DCDC) >> 6);

    if(modules & MADC)   // check if the ADC is enabled
    {
      // This transmission connects the resistive divider to MB and BB.
      ABB_WriteRegister(BCICTL1, 0x0005);
    }
  #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
    // Restore the ABB checks and debouncing if start on TESTRESETZ

    // This transmission changes the register page in the ABB for usp to pg1.
    ABB_SetPage(PAGE1);

    // This transmission sets the AFCCK to CKIN/2.
    ABB_WriteRegister(AFCCTLADD, 0x01);

    // This transmission enables the tapreg.
    ABB_WriteRegister(TAPCTRL, 0x01);

    // This transmission enables access to page 2.
    ABB_WriteRegister(TAPREG, 0x01b);

    // This transmission changes the register page in the ABB for usp to pg2.
    ABB_SetPage(PAGE2);

    #if (ANLG_FAM == 2)
    // Restore push button environment
    ABB_WriteRegister(0x3C, 0x07);

    #elif (ANLG_FAM == 3)

    // Restore push button environment
    ABB_WriteRegister(0x3C, 0xBF);

      /* ************************  SELECTION OF BBCFG CONFIG FOR ABB 3 PG1_0 *******************************/
        #if (ANLG_PG == S_PG_10)                    // SYREN PG1.0 ON ESAMPLE
          ABB_WriteRegister(BBCFG, C_BBCFG);         // Initialize transmit register
        #endif
    // This transmission enables access to page 0.
    ABB_SetPage(PAGE0);

    // reset bit MSKINT1 , if set by TESTRESET
    reg=ABB_ReadRegister(VRPCSTS) & 0xffe;

    ABB_WriteRegister(VRPCSTS, reg);

    ABB_SetPage(PAGE2);

    // Restore default for BG behavior in sleep mode
    ABB_WriteRegister(VRPCAUX, 0xBF);

    // Restore default for deboucing length
    ABB_WriteRegister(VRPCLDO, 0x00F);

    // Restore default for INT1 generation, wait time in switch on, checks in switch on
    ABB_WriteRegister(VRPCABBTST, 0x0002);

    #endif

    // This transmission changes the register page in the ABB for usp to pg1.
    ABB_SetPage(PAGE1);

    // This transmission sets tapinst to id code.
    ABB_WriteRegister(TAPREG, 0x0001);

    // This transmission disables TAPREG access.
    ABB_WriteRegister(TAPCTRL, 0x00);

    // enable BB battery charge BCICONF register, enable test mode to track BDLEN and BULEN windows
    // This transmission enables BB charge and BB bridge connection for BB measurements.
#if ENABLE_BACKUP_BATTERY
    ABB_WriteRegister(BCICONF, 0x060);
#else
    ABB_WriteRegister(BCICONF, 0x000);
#endif

     /* ************************  SELECTION OF BBCFG CONFIG FOR ABB 3 PG2_0 *******************************/
      #if (ANLG_FAM == 3)
        #if (ANLG_PG == S_PG_20)                     // SYREN PG2.0 ON EVACONSO
           ABB_WriteRegister(BBCFG, C_BBCFG);         // Initialize transmit register
        #endif
      #endif

    /* ************************  SELECTION OF TEST MODE FOR ABB ******************************************/
    /* This test configuration allows visibility on test pins  TAPCTRL has not to be reset                */
    /* ****************************************************************************************************/

    // This transmission enables the tapreg.
    ABB_WriteRegister(TAPCTRL, 0x01);

    // This transmission select ABB test instruction.
    ABB_WriteRegister(TAPREG, TSPEN);

    // This transmission changes the register page in ABB for usp to pg0.
    ABB_SetPage(PAGE0);

    // This transmission enables selected ABB modules.
    ABB_WriteRegister(TOGBR1, modules >> 6);

    // enable MB & BB resistive bridges for measurements
    if(modules & MADC)       // check if the ADC is enabled
    {
      // This transmission connects the resistive divider to MB and BB.
      ABB_WriteRegister(BCICTL1, 0x0001);
    }

    /********* Sleep definition part ******************/
    // This transmission changes the register page in the ABB for usp to pg1.
    #if (ANLG_FAM == 2)
      ABB_SetPage(PAGE1);

      // update the Delay needed by the ABB before going in deep sleep, and clear previous delay value.
      reg = ABB_ReadRegister(VRPCCFG) & 0x1e0;

      ABB_WriteRegister(VRPCCFG, (SLPDLY | reg));

      // update the ABB mask sleep register (regulator disabled in deep sleep), and clear previous mask value.
      reg = ABB_ReadRegister(VRPCMSK) & 0x1e0;
      ABB_WriteRegister(VRPCMSK, (MASK_SLEEP_MODE | reg));
    #elif (ANLG_FAM == 3)
         Syren_Sleep_Config(NORMAL_SLEEP,SLEEP_BG,SLPDLY);
    #endif
    //  This transmission changes the register page in the ABB for usp to pg0.
    ABB_SetPage(PAGE0);
  #endif

  // SW workaround for initialization of the audio parts of the ABB to avoid white noise
  // C.f. BUG1941
  // Set VDLR and VULR bits
  // Write TOGBR1 register
  // This transmission enables selected ABB modules.
  ABB_WriteRegister(TOGBR1, 0x0A);

  // wait for 1 ms
  wait_ARM_cycles(convert_nanosec_to_cycles(1000000));

  // Reset VDLS and VULS bits
  // Write TOGBR1 register
  // This transmission enables selected ABB modules.
  ABB_WriteRegister(TOGBR1, 0x05);

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if (ABB_SEMAPHORE_PROTECTION == 3)
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION
}


/*-----------------------------------------------------------------------*/
/* ABB_Read_ADC()                                                        */
/*                                                                       */
/* This function manages all the spi serial transfer to read all the     */
/* ABB ADC conversion channels.                                          */
/* Stores the result in Buff parameter.                                  */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Read_ADC(SYS_UWORD16 *Buff)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;

  #if (ABB_SEMAPHORE_PROTECTION == 3)

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for RD and WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_RDWR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  // This transmission changes the register page in the ABB for usp to pg0.
  ABB_SetPage(PAGE0);

  /* Read all ABB ADC registers */
  *Buff++ = ABB_ReadRegister(VBATREG);
  *Buff++ = ABB_ReadRegister(VCHGREG);
  *Buff++ = ABB_ReadRegister(ICHGREG);
  *Buff++ = ABB_ReadRegister(VBKPREG);
  *Buff++ = ABB_ReadRegister(ADIN1REG);
  *Buff++ = ABB_ReadRegister(ADIN2REG);
  *Buff++ = ABB_ReadRegister(ADIN3REG);

  #if (ANLG_FAM == 1)
    *Buff++ = ABB_ReadRegister(ADIN4XREG);
    *Buff++ = ABB_ReadRegister(ADIN5YREG);
  #elif (ANLG_FAM == 2)
    *Buff++ = ABB_ReadRegister(ADIN4REG);
  #elif (ANLG_FAM == 3)
    *Buff++ = ABB_ReadRegister(ADIN4REG);
    *Buff++ = ABB_ReadRegister(ADIN5REG);
  #endif   // ANLG_FAM

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if (ABB_SEMAPHORE_PROTECTION == 3)
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION
}


/*-----------------------------------------------------------------------*/
/* ABB_Conf_ADC()                                                        */
/*                                                                       */
/* This function manages all the spi serial transfer to:                 */
/*  - select the ABB ADC channels to be converted                        */
/*  - enable/disable EOC interrupt                                       */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Conf_ADC(SYS_UWORD16 Channels, SYS_UWORD16 ItVal)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;
  SYS_UWORD16 reg_val;

  #if (ABB_SEMAPHORE_PROTECTION == 3)

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for RD and WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_RDWR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  // This transmission changes the register page in the ABB for usp to pg0.
  ABB_SetPage(PAGE0);

  /* select ADC channels to be converted */
  #if (ANLG_FAM == 1)
    ABB_WriteRegister(MADCCTRL1, Channels);
  #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
    ABB_WriteRegister(MADCCTRL, Channels);
  #endif

  reg_val = ABB_ReadRegister(ITMASK);

  // This transmission configure the End Of Conversion IT without modifying other bits in the same register.
  if(ItVal == EOC_INTENA)
    ABB_WriteRegister(ITMASK, reg_val & EOC_INTENA);
  else if(ItVal == EOC_INTMASK)
    ABB_WriteRegister(ITMASK, reg_val | EOC_INTMASK);

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if (ABB_SEMAPHORE_PROTECTION == 3)
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION
}


/*------------------------------------------------------------------------*/
/* ABB_sleep()                                                            */
/*                                                                        */
/* This function disables the DCDC and returns to PAGE 0. It stops then   */
/* the 13MHz clock in ABB. A wait loop s required to allow                */
/* first slow access to ABB clock register.                               */
/*                                                                        */
/* WARNING !! : this function must not be protected by semaphore !!       */
/*                                                                        */
/* Returns AFC value.                                                     */
/*                                                                        */
/*------------------------------------------------------------------------*/
SYS_UWORD32 ABB_sleep(SYS_UWORD8 sleep_performed, SYS_WORD16 afc)
{
  volatile SYS_UWORD16 status;
  SYS_UWORD32 afcout_index;
  volatile SYS_UWORD16 nb_it;
  SYS_UWORD16 reg_val;

  // table for AFC allowed values during Sleep mode. First 5th elements
  // are related to positive AFC values, last 5th to negative ones.
  SYS_UWORD32 Afcout_T[10]= {0x0f,0x1f,0x3f,0x7f,0xff,0x00,0x01,0x03,0x07,0x0f};

  // Start spi clock, mask IT for RD and WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_RDWR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  // COMPUTATION AND PROGRAMMING OF AFC VALUE
  //---------------------------------------------------
  if(afc & 0x1000)
    afcout_index = ((afc + 512)>>10) + 1;
  else
    afcout_index = (afc  + 512)>>10;

  if (sleep_performed == FRAME_STOP)   // Big sleep
  {
    #if ((ANLG_FAM == 2) || (ANLG_FAM == 3))
      //////////// ADD HERE IOTA or SYREN CONFIGURATION FOR BIG SLEEP ////////////////////////////
    #endif

  }
  else                                  // Deep sleep
  {
    #if(ANLG_FAM == 1)
      // SELECTION OF AFC TEST MODE FOR OMEGA
      //---------------------------------------------------
      // This test configuration allows access on the AFCOUT register
      ABB_SetPage(PAGE1);

      // This transmission enables OMEGA test register.
      ABB_WriteRegister(TAPCTRL, 0x01);

      // This transmission selects OMEGA test instruction.
      ABB_WriteRegister(TAPREG, AFCTEST);

      // Set AFCOUT to 0.
      ABB_WriteRegister(AFCOUT, 0x00 >> 6);

      ABB_SetPage(PAGE0);

    #elif (ANLG_FAM == 2)
      // This configuration allows access on the AFCOUT register
      ABB_SetPage(PAGE1);

      // Read AFCCTLADD value and enable USP access to AFCOUT register
      reg_val = (ABB_ReadRegister(AFCCTLADD) | 0x04);

      ABB_WriteRegister(AFCCTLADD, reg_val);

      // Set AFCOUT to 0.
      ABB_WriteRegister(AFCOUT, 0x00);

#if ENABLE_BACKUP_BATTERY
      // Read BCICONF value	and cut the measurement bridge of BB cut the BB charge.
      reg_val = ABB_ReadRegister(BCICONF) & 0x039f;

      ABB_WriteRegister(BCICONF, reg_val);
#endif

      // Disable the ABB test mode
      ABB_WriteRegister(TAPCTRL, 0x00);

      ABB_SetPage(PAGE0);

      // Read BCICTL1 value and cut the measurement bridge of MB.
      reg_val = ABB_ReadRegister(BCICTL1) & 0x03fe;

      ABB_WriteRegister(BCICTL1, reg_val);
    #endif

     #if (ANLG_FAM == 3)              // Nothing to be done as MB and BB measurement bridges are automatically disconnected
                                              // in Syren during sleep mode. BB charge stays enabled
       ABB_SetPage(PAGE1);                    // Initialize transmit reg_num. This transmission
                                              // change the register page in IOTA for usp to pg1

       ABB_WriteRegister(TAPCTRL, 0x00);      // Disable Syren test mode

       ABB_SetPage(PAGE0);
     #endif

    // switch off MADC, AFC, AUXDAC, VOICE.
    ABB_WriteRegister(TOGBR1, 0x155);

    // Switch off Analog supply LDO
    //-----------------------------
    #if (ANLG_FAM == 1)
      ABB_SetPage(PAGE1);

      // Read VRPCCTL3 register value and switch off VR3.
      reg_val = ABB_ReadRegister(VRPCCTRL3) & 0x3df;

      ABB_WriteRegister(VRPCCTRL3, reg_val);

    #elif (ANLG_FAM == 2)
      // Read VRPCSTS register value and extract status of meaningfull inputs.
      reg_val = ABB_ReadRegister(VRPCSTS) & 0x0070;

    #ifdef ABB_SLEEP_RESTRICTION
      if (reg_val == 0x30 && ABB_sleep_allowed)
    #else
      if (reg_val == 0x30)
    #endif
      {
        // start the SLPDLY counter in order to switch the ABB in sleep mode. This transmission sets IOTA sleep bit.
        ABB_WriteRegister(VRPCDEV, 0x02);
      }

      // Dummy transmission to clean of ABB bus. This transmission accesses IOTA address 0 in "read".
      ABB_WriteRegister(0x0000 | 0x0001, 0x0000);

    #elif (ANLG_FAM == 3)
       // In Syren there is no need to check for VRPCCFG as wake up prioritys are changed
       // start the SLPDLY counter in order to switch the ABB in sleep mode
       ABB_WriteRegister(VRPCDEV,0x02);     // Initialize transmit reg_num. This transmission
                                            // set Syren sleep bit
/*
      // Dummy transmission to clean of ABB bus. This transmission accesses SYREN address 0 in "read".
      ABB_WriteRegister(0x0000 | 0x0001, 0x0000);
*/
    #endif

    // Switch to low frequency clock
    ABB_stop_13M();
  }

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

#if (OP_L1_STANDALONE == 1)
   #if (CHIPSET == 12)
       // GPIO_InitAllPull(ALL_ONE);  // enable all GPIO internal pull
       // workaround to set APLL_DIV_CLK( internal PU) at high level
       // by default APLL_DIV_CLK is low pulling 80uA on VRIO
//       *(SYS_UWORD16*) (0xFFFFFD90)= 0x01;//CNTL_APLL_DIV_CLK -> APLL_CLK_DIV != 0
//       *(SYS_UWORD16*) (0xFFFEF030)= 0x10;// DPLL mode
   #endif
#endif
  return(Afcout_T[afcout_index]);
}


/*------------------------------------------------------------------------*/
/* ABB_wakeup()                                                           */
/*                                                                        */
/* This function sets the 13MHz clock working in ABB. A wait loop         */
/* is required to allow first slow access to ABB clock register.          */
/* Then it re-enables DCDC and returns to PAGE 0.                         */
/*                                                                        */
/* WARNING !! : this function must not be protected by semaphore !!       */
/*                                                                        */
/*------------------------------------------------------------------------*/
void ABB_wakeup(SYS_UWORD8 sleep_performed, SYS_WORD16 afc)
{
  volatile SYS_UWORD16 status;
  SYS_UWORD16 reg_val;

  // Start spi clock, mask IT for RD and WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_RDWR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  if (sleep_performed == FRAME_STOP)   // Big sleep
  {
    #if ((ANLG_FAM == 2) || (ANLG_FAM == 3))
      //////////// ADD HERE IOTA or SYREN CONFIGURATION FOR BIG SLEEP WAKEUP ////////////////////////////
    #endif
  }
  else                                  // Deep sleep
  {
    #if (OP_L1_STANDALONE == 1)
      #if (CHIPSET == 12)
         // restore context from
         // workaround to set APLL_DIV_CLK( internal PU) at high level
         // by default APLL_DIV_CLK is low pulling 80uA on VRIO
//         *(SYS_UWORD16*) (0xFFFFFD90)= 0x00;//CNTL_APLL_DIV_CLK -> APLL_DIV_CLK != 0
//         *(SYS_UWORD16*) (0xFFFEF030)= 0x00;// DPLL mode
      #endif
    #endif

    // Restitutes 13MHZ Clock to ABB
    ABB_free_13M();

    // Switch ON Analog supply LDO
    #if (ANLG_FAM == 1)
      ABB_SetPage(PAGE1);

      // Read VRPCCTL3 register value and switch on VR3.
      reg_val = ABB_ReadRegister(VRPCCTRL3) | 0x020;

      ABB_WriteRegister(VRPCCTRL3, reg_val);
      ABB_SetPage(PAGE0);
    #endif

    // This transmission switches on MADC, AFC.
    ABB_WriteRegister(TOGBR1, 0x280);

    // This transmission sets the AUXAFC2.
    ABB_WriteRegister(AUXAFC2, ((afc>>10) & 0x7));

    // This transmission sets the AUXAFC1.
    ABB_WriteRegister(AUXAFC1, (afc & 0x3ff));

    #if (ANLG_FAM == 1)
      // Remove AFC test mode
      ABB_SetPage(PAGE1);

      // This transmission select Omega test instruction.
      ABB_WriteRegister(TAPREG, TSPTEST1);

      // Disable test mode selection
      // This transmission disables Omega test register.
      ABB_WriteRegister(TAPCTRL, 0x00 >> 6);

      ABB_SetPage(PAGE0);

    #elif (ANLG_FAM == 2)
      ABB_SetPage(PAGE1);

      // Read AFCCTLADD register value and disable USP access to AFCOUT register.
      reg_val = ABB_ReadRegister(AFCCTLADD) & ~0x04;

      ABB_WriteRegister(AFCCTLADD, reg_val);

#if ENABLE_BACKUP_BATTERY
      // Read BCICONF register value and enable BB measurement bridge enable BB charge.
      reg_val = ABB_ReadRegister(BCICONF) | 0x0060;

      ABB_WriteRegister(BCICONF, reg_val);
#endif


      /* *************************************************************************************************** */
      // update the Delay needed by the ABB before going in deep sleep, and clear previous delay value.
      reg_val = ABB_ReadRegister(VRPCCFG) & 0x1e0;
      ABB_WriteRegister(VRPCCFG, (SLPDLY | reg_val));

      // Enable the ABB test mode
      ABB_WriteRegister(TAPCTRL, 0x01);
      ABB_WriteRegister(TAPREG, TSPEN);
      ABB_SetPage(PAGE0);

      // Read BCICTL1 register value and enable MB measurement bridge and cut the measurement bridge of MB.
      reg_val = ABB_ReadRegister(BCICTL1) | 0x0001;

      ABB_WriteRegister(BCICTL1, reg_val);
    #endif

  #if (ANLG_FAM == 3)

    ABB_SetPage(PAGE1);

    /* *************************************************************************************************** */
    // update the Delay needed by the ABB before going in deep sleep, and clear previous delay value.
    reg_val = ABB_ReadRegister(VRPCCFG) & 0x1e0;
    ABB_WriteRegister(VRPCCFG, (SLPDLY | reg_val));

    /* ************************  SELECTION OF TEST MODE FOR ABB=3 *****************************************/
    /* This test configuration allows visibility on test pins  TAPCTRL has not to be reset                */
    /* ****************************************************************************************************/

    ABB_WriteRegister(TAPCTRL, 0x01);             // Initialize the transmit register
                                                  // This transmission enables IOTA test register

    ABB_WriteRegister(TAPREG, TSPEN);
                                                  // This transmission select IOTA test instruction
                                                  // This transmission select IOTA test instruction
    /**************************************************************************************************** */

    ABB_SetPage(PAGE0);                          // Initialize transmit reg_num. This transmission
  #endif
  }

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif
}

/*------------------------------------------------------------------------*/
/* ABB_wa_VRPC()                                                          */
/*                                                                        */
/* This function initializes the VRPCCTRL1 or VRPCSIM register            */
/* according to the ABB used.                                             */
/*                                                                        */
/*------------------------------------------------------------------------*/
void ABB_wa_VRPC(SYS_UWORD16 value)
{
  volatile SYS_UWORD16 status;
  STATUS sem_status;

  #if ((ABB_SEMAPHORE_PROTECTION == 1) || (ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_WR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  ABB_SetPage(PAGE1);

  #if (ANLG_FAM == 1)
    // This transmission initializes the VRPCCTL1 register.
    ABB_WriteRegister(VRPCCTRL1, value);

  #elif (ANLG_FAM == 2)
    // This transmission initializes the VRPCSIM register.
    ABB_WriteRegister(VRPCSIM, value);

  #elif (ANLG_FAM == 3)
    // This transmission initializes the VRPCSIMR register.
    ABB_WriteRegister(VRPCSIMR, value);

  #endif

  ABB_SetPage(PAGE0);

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if ((ABB_SEMAPHORE_PROTECTION == 1) || (ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION
}


/*-----------------------------------------------------------------------*/
/* ABB_Write_Uplink_Data()                                               */
/*                                                                       */
/* This function uses the SPI to write to ABB uplink buffer.             */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Write_Uplink_Data(SYS_UWORD16 *TM_ul_data)
{
  SYS_UWORD8 i;
  volatile SYS_UWORD16 status;
  STATUS sem_status;

  #if ((ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))

  // check if the semaphore has been correctly created and try to obtain it.
  // if the semaphore cannot be obtained, the task is suspended and then resumed
  // as soon as the semaphore is released.

  sem_status = NU_Obtain_Semaphore(&abb_sem, NU_SUSPEND);

  #endif  // ABB_SEMAPHORE_PROTECTION

  // Start spi clock, mask IT for WR and read SPI_REG_STATUS to reset the RE and WE flags.
  SPI_Ready_for_WR
  status = * (volatile SYS_UWORD16 *) SPI_REG_STATUS;

  // Select Page 0 for TOGBR2
  ABB_SetPage(PAGE0);

  // Initialize pointer of burst buffer 1 : IBUFPTR is bit 10 of TOGBR2
  ABB_WriteRegister(TOGBR2, 0x10);

  // Clear, assuming that it works like IBUFPTR of Vega
  ABB_WriteRegister(TOGBR2, 0x0);

  // Write the ramp data
  for (i=0;i<16;i++)
    ABB_WriteRegister(BULDATA1_2, TM_ul_data[i]>>6);

  // Stop the SPI clock
  #ifdef SPI_CLK_LOW_POWER
    SPI_CLK_DISABLE
  #endif

  #if ((ABB_SEMAPHORE_PROTECTION == 2) || (ABB_SEMAPHORE_PROTECTION == 3))
  // release the semaphore only if it has correctly been created.
  if(sem_status == NU_SUCCESS)
  {
    NU_Release_Semaphore(&abb_sem);
  }
  #endif  // ABB_SEMAPHORE_PROTECTION
}

//////////////////////// IDEV-INLO integration of sleep mode for Syren ///////////////////////////////////////

#if (ANLG_FAM == 3)

  // Syren Sleep configuration function --------------------------
  void Syren_Sleep_Config(SYS_UWORD16 sleep_type,SYS_UWORD16 bg_select, SYS_UWORD16 sleep_delay)
  {
    volatile SYS_UWORD16 status,sl_ldo_stat;

    ABB_SetPage(PAGE1);                            // Initialize transmit register. This transmission
                                                   // change the register page in ABB for usp to pg1

    ABB_WriteRegister(VRPCCFG, sleep_delay);       // write delay value

    sl_ldo_stat = ((sleep_type<<9|bg_select<<8) & 0x0374);

    ABB_WriteRegister(VRPCMSKSLP, sl_ldo_stat);     // write sleep ldo configuration

    ABB_SetPage(PAGE0);                            // Initialize transmit register. This transmission
                                                   // change the register page in ABB for usp to pg0
  }
#endif


#if (OP_L1_STANDALONE == 0)
/*-----------------------------------------------------------------------*/
/* ABB_Power_Off()                                                       */
/*                                                                       */
/* This function uses the SPI to switch off the ABB.                     */
/*                                                                       */
/*-----------------------------------------------------------------------*/
void ABB_Power_Off(void)
{
  // Wait until all necessary actions are performed (write in FFS, etc...) to power-off the board (empirical value - 30 ticks).
  NU_Sleep (30);

  // Wait also until <ON/OFF> key is released.
  // This is needed to avoid, if the power key is pressed for a long time, to switch
  // ON-switch OFF the mobile, until the power key is released.
  #if((ANLG_FAM == 1) || (ANLG_FAM == 2))
    while ((ABB_Read_Status() & ONREFLT) == PWR_OFF_KEY_PRESSED) {
  #elif(ANLG_FAM == 3)
    while ((ABB_Read_Register_on_page(PAGE1, VRPCCFG) & PWOND) == PWR_OFF_KEY_PRESSED) {
  #endif

  NU_Sleep (1); }

  BZ_KeyBeep_OFF();

  #if(ANLG_FAM == 1)
    ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE);
  #elif((ANLG_FAM == 2) || (ANLG_FAM == 3))
    ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001);
  #endif
}
#endif