/*******************************************************************************
* FILE NAME: etpu_pmsmvc.c          COPYRIGHT (c) Freescale Semiconductor 2006
*                                               All Rights Reserved
* DEPMSMVCRIPTION:
* This file contains the eTPU Permanent Magnet Synchronous Motor Vector Control
* (PMSMVC) API.
*===============================================================================
* REV      AUTHOR      DATE        DESCRIPTION OF CHANGE
* ---   -----------  ----------    ---------------------
* 0.1   M. Brejl     22/Aug/05     Initial file version.
* 2.0   M. Brejl     22/Aug/05     Clean up of compiler warnings.
* 2.1   M. Princ     17/Mar/06     Corrections due to the new implementation
*                                  of ripple elimination.
* 2.2   M. Brejl     27/Jan/12     Support of RSLV usage added.
* 2.3   M. Brejl     30/Mar/12     Compensation delay added.
* 2.4   M. Brejl     25/Apr/12     Addition of fs_etpu_pmsmvc_get_u_dq_clim()
*******************************************************************************/
#include "etpu_util.h"          /* Utility routines for working with the eTPU */
#include "etpu_pmsmvc.h"        /* eTPU PMSMVC API */

extern uint32_t fs_etpu_data_ram_start;
extern uint32_t fs_etpu_data_ram_ext;
extern uint32_t etpu_a_tcr1_freq;
extern uint32_t etpu_a_tcr2_freq;
extern uint32_t etpu_b_tcr1_freq;
extern uint32_t etpu_b_tcr2_freq;

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_init
*PURPOSE      : This routine is used to initialize the eTPU channel for the 
*               PMSMVC function.
*INPUTS NOTES : This function has 18 parameters:
*  channel            - This is the PMSMVC channel number.
*                       0-31 for ETPU_A and 64-95 for ETPU_B.
*  priority           - This is the priority to assign to the PMSMVC function.
*                       This parameter should be assigned a value of:
*                       FS_ETPU_PRIORITY_HIGH or
*                       FS_ETPU_PRIORITY_MIDDLE or
*                       FS_ETPU_PRIORITY_LOW or
*                       FS_ETPU_PRIORITY_DISABLED.
*  mode               - This is the function mode.
*                       This parameter should be assigned a value of:
*                       FS_ETPU_PMSMVC_MASTER or
*                       FS_ETPU_PMSMVC_SLAVE.
*  circle_limitation_config - This is the required configuration of Circle 
*                       Limitation.
*                       This parameter should be assigned a value of:
*                       FS_ETPU_PMSMVC_CIRCLE_LIMITATION_OFF or
*                       FS_ETPU_PMSMVC_CIRCLE_LIMITATION_ON.
*  period             - This is the update period, as number of TCR1 clocks.
*                       This parameter applies in the Master
*                       Mode only (mode=FS_ETPU_PMSMVC_MASTER).
*  start_offset       - This parameter is used to synchronize various
*                       eTPU functions that generate a signal.
*                       The first PMSMVC update starts the start_offset TCR1
*                       clocks after initialization. This parameter applies
*                       in the Master Mode only (mode=FS_ETPU_PMSMVC_MASTER).
*  services_per_irq   - This parameter defines the number of updates after
*                       which an interrupt service request is generated
*                       to the CPU.
*  SC_chan            - This is the number of a channel the SC function is
*                       assigned to. The PMSMVC reads the actual speed from SC.
*                       0-31 for ETPU_A and 64-95 for ETPU_B.
*  QD_RSLV_chan       - This is the number of a channel the QD or RSLV function
*                       is assigned to. The PMSMVC reads the motor position from
*                       QD or RSLV.
*                       0-31 for ETPU_A and 64-95 for ETPU_B.
*  qd_pc_per_rev      - This is the number of QD Position Counter increments
*                       per revolution. If QD is not used, set it to 0.
*  rslv_pole_pairs    - This is the number of Resolver pole pairs. If RSLV is 
*                       not used, set it to 0.
*  motor_pole_pairs   - This parameter defines the number of motor pole-pairs.
*  p_motor_params     - This is the pointer to a pmsmvc_motor_params_t structure
*                       of motor constants:
*                       Ke - motor electrical constant in fractional format 
*                            (3.21). It’s value must be scaled to nominal range:
*                            Ke[-] = 2*pi * Ke[V/RPM] * pole_pairs * 
*                                    speed_range[RPM] / dc_bus_voltage_range[V]
*                            and then expressed in fractional format 3.21:
*                            Ke[fract 3.21] = 0x200000 * Ke[-]
*                       Ld - motor induction in D-coordinate in fractional 
*                            format (3.21). It’s value must be scaled to nominal
*                            range:
*                            Ld[-]= 2*pi * Ld[H] * pole_pairs * speed_range[RPM]
*                                   * current_range[A]
*                                   / (60 * dc_bus_voltage_range[V])
*                            and then expressed in fractional format 3.21:
*                            Ld[fract 3.21] = 0x200000 * Ld[-]
*                       Lq - motor induction in Q-coordinate in fractional 
*                            format (3.21). It’s value must be scaled the same 
*                            way as Ld.
*                       The Ld and Lq are usually (but not always) equal.
*  p_pid_d_params     - This is the pointer to a pmsmvc_pid_params_t structure
*                       of D-coordinate PID controller parameters.
*  p_pid_q_params     - This is the pointer to a pmsmvc_pid_params_t structure
*                       of Q-coordinate PID controller parameters.
*  inv_mod_index      - This parameter defines the Inverse Modulation Index.
*                       Inverse Modulation Index is dependent on the type of 
*                       modulation technique being used by PWMMAC.
*                       This parameter should be assigned a value of:
*                       FS_ETPU_PMSMVC_INVMODINDEX_SINE,
*                       FS_ETPU_PMSMVC_INVMODINDEX_SIN3H, or
*                       FS_ETPU_PMSMVC_INVMODINDEX_SVM.
*  -------------+------------+---------------+----------------------------------
*  Modulation   | Inverse    | inv_mod_index | #define
*  Type         | Mod. Index | (fract 1.23)  | constant
*  -------------+------------+---------------+----------------------------------
*  Sine Wave    | 1.000000   |  0x7FFFFF     | FS_ETPU_PMSMVC_INVMODINDEX_SINE
*  Sine 3rd harm| 0.866025   |  0x6ED9EC     | FS_ETPU_PMSMVC_INVMODINDEX_SIN3H
*  Space Vector | 0.866025   |  0x6ED9EC     | FS_ETPU_PMSMVC_INVMODINDEX_SVM
*  -------------+------------+---------------+----------------------------------
*  output_chan        - PMSMVC writes outputs to a recipient function
*                       input parameters. This is the recipient function
*                       channel number. If PMSMVC updates PWM duty-cycles 
*                       it should be a PWMMAC channel.
*                       0-31 for ETPU_A and 64-95 for ETPU_B.
*  output_offset      - PMSMVC writes outputs to a recipient function
*                       input parameters. This is the first input parameter 
*                       offset of the recipient function. If PMSMVC updates
*                       PWM duty-cycles it should be 
*                       FS_ETPU_PWMMAC_INPUTS_OFFSET.
*                       Function parameter offsets are defined in
*                       etpu_<func>_auto.h file.
*  link_chan          - This is the channel number of a channel which receives
*                       a link after PMSMVC updates output. If PMSMVC updates
*                       PWM duty-cycles it should be a PWMMAC channel.
*                       0-31 for ETPU_A and 64-95 for ETPU_B.
*  compensation_delay - This is the delay from the point where the phase 
*                       currents and motor position are measured to the point
*                       where the new PWM duty-cycles are applied, expressed as:
*                                            Comp_Delay[TCR1] * Omega_Range[RPM]
*                       compensation_delay = -----------------------------------
*                                                   30 * freq_tcr1[Hz]
*                       Typically, 1.5 x the PWM period is used for
*                       Comp_Delay[TCR1].
*                       If this parameter is assigned 0, the delay compensation
*                       task is turned off.
*
*RETURNS NOTES: Error codes which can be returned are: FS_ETPU_ERROR_VALUE,
*               FS_ETPU_ERROR_MALLOC
*******************************************************************************/
int32_t fs_etpu_pmsmvc_init( uint8_t channel,
                             uint8_t priority,
                             uint8_t mode,
                             uint8_t circle_limitation_config,
                            uint24_t period,
                            uint24_t start_offset,
                            uint24_t services_per_irq,
                             uint8_t SC_chan,
                             uint8_t QD_RSLV_chan,
                            uint24_t qd_pc_per_rev,
                             uint8_t rslv_pole_pairs,
                             uint8_t motor_pole_pairs,
              pmsmvc_motor_params_t* p_motor_params,
                pmsmvc_pid_params_t* p_pid_d_params,
                pmsmvc_pid_params_t* p_pid_q_params,
                             int24_t inv_mod_index,
                             uint8_t output_chan,
                            uint16_t output_offset,
                             uint8_t link_chan,
                            uint24_t compensation_delay)
{
   uint32_t * pba;
   uint32_t * pba_pid_d;
   uint32_t * pba_pid_q;
   uint8_t  pid_options_d;
   uint8_t  pid_options_q;
   uint32_t scale;
   uint32_t output_addr;
   uint32_t position_addr;
   uint32_t omega_actual_addr;

   /***************************************
   * Parameters bounds check.
   ***************************************/
   #ifdef FS_ETPU_MC_PARAM_CHECK
   if(((channel>31)&&(channel<64))||(channel>95)||
      (priority>FS_ETPU_PRIORITY_HIGH)||
      (mode>FS_ETPU_PMSMVC_MASTER)||
      (circle_limitation_config>FS_ETPU_PMSMVC_CIRCLE_LIMITATION_ON)||
      (period>0x800000)||
      (start_offset>0x800000)||
      ((SC_chan>31)&&(SC_chan<64))||(SC_chan>95)||
      ((QD_RSLV_chan>31)&&(QD_RSLV_chan<64))||(QD_RSLV_chan>95)||
      ((link_chan>31)&&(link_chan<64))||(link_chan>95)||
      ((output_chan>31)&&(output_chan<64))||(output_chan>95))
   {
      return(FS_ETPU_ERROR_VALUE);
   }
   #endif

   /***************************************
   * PRAM allocation.
   ***************************************/
   /* channel parameters allocation. */
   if ((pba=fs_etpu_malloc(FS_ETPU_PMSMVC_NUM_PARMS)) == 0)
   {
      return(FS_ETPU_ERROR_MALLOC);
   }
   /* D-PID structure allocation. */
   if ((pba_pid_d=fs_etpu_malloc(FS_ETPU_MC_CTRL_PID_STR_SIZE)) == 0)
   {
      return(FS_ETPU_ERROR_MALLOC);
   }
   /* Q-PID structure allocation. */
   if ((pba_pid_q=fs_etpu_malloc(FS_ETPU_MC_CTRL_PID_STR_SIZE)) == 0)
   {
      return(FS_ETPU_ERROR_MALLOC);
   }

   /***************************************
   * Write chan config register.
   ***************************************/
   eTPU->CHAN[channel].CR.R = (FS_ETPU_PMSMVC_TABLE_SELECT << 24) +
                              (FS_ETPU_PMSMVC_FUNCTION_NUMBER << 16) +
                              (((uint32_t)pba - fs_etpu_data_ram_start) >> 3);
   eTPU->CHAN[channel].SCR.R = (uint32_t)circle_limitation_config;

   /***************************************
   * Write parameters.
   ***************************************/
   if(qd_pc_per_rev != 0)
   {
      position_addr = (uint32_t)((eTPU->CHAN[QD_RSLV_chan].CR.B.CPBA << 3) + 
                      FS_ETPU_QD_PC_OFFSET);
      scale = motor_pole_pairs*0x1000000/qd_pc_per_rev;
   }
   else if(rslv_pole_pairs != 0)
   {
      position_addr = (uint32_t)((eTPU->CHAN[QD_RSLV_chan].CR.B.CPBA << 3) + 
                      FS_ETPU_RSLV_RESANGLEWITHOFFSET_OFFSET);
      scale = motor_pole_pairs/rslv_pole_pairs;
   }
   else
   {
      return(FS_ETPU_ERROR_VALUE);
   }
   output_addr = (uint32_t)((eTPU->CHAN[output_chan].CR.B.CPBA << 3) + 
                 output_offset);
   omega_actual_addr = (uint32_t)((eTPU->CHAN[SC_chan].CR.B.CPBA << 3) + 
                       FS_ETPU_SC_OMEGAACTUAL_OFFSET);

   /* write channel parameters */
   *(pba + ((FS_ETPU_PMSMVC_PERIOD_OFFSET         - 1)>>2)) = period;
   *(pba + ((FS_ETPU_PMSMVC_STARTOFFSET_OFFSET    - 1)>>2)) = start_offset;
   *(pba + ((FS_ETPU_PMSMVC_SERVICESPERIRQ_OFFSET - 1)>>2)) = services_per_irq;
   *(pba + ((FS_ETPU_PMSMVC_KLD_OFFSET            - 1)>>2)) = 
                                            (uint32_t)p_motor_params->Ld;
   *(pba + ((FS_ETPU_PMSMVC_KLQ_OFFSET            - 1)>>2)) = 
                                            (uint32_t)p_motor_params->Lq;;
   *(pba + ((FS_ETPU_PMSMVC_KE_OFFSET             - 1)>>2)) = 
                                            (uint32_t)p_motor_params->Ke;;
   *(pba + ((FS_ETPU_PMSMVC_INVMODINDEX_OFFSET    - 1)>>2)) = 
                                            (uint32_t)inv_mod_index;
   *(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET              )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET           + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET           + 8)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IAB_OFFSET               )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IAB_OFFSET            + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IDQ_OFFSET               )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IDQ_OFFSET            + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IDQDESIRED_OFFSET        )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_IDQDESIRED_OFFSET     + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_UDQ_OFFSET               )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_UDQ_OFFSET            + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_UDQCLIM_OFFSET           )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_UDQCLIM_OFFSET        + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_UAB_OFFSET               )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_UAB_OFFSET            + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_POUTPUTS_OFFSET          )>>2)) = 
                                            output_addr & 0x1FFF;
   *(pba + ((FS_ETPU_PMSMVC_PQDPCRSLVANGLE_OFFSET - 1)>>2)) = 
                                            position_addr & 0x1FFF;
   *(pba + ((FS_ETPU_PMSMVC_SCALE_OFFSET          - 1)>>2)) = scale;
   *(pba + ((FS_ETPU_PMSMVC_THETA_OFFSET          - 1)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_SINCOS_OFFSET            )>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_SINCOS_OFFSET         + 4)>>2)) = 0;
   *(pba + ((FS_ETPU_PMSMVC_PSCOMEGAACTUAL_OFFSET - 1)>>2)) = 
                                            omega_actual_addr & 0x1FFF;
   *(pba + ((FS_ETPU_PMSMVC_PPIDD_OFFSET          - 1)>>2)) = 
                         ((uint32_t)pba_pid_d - fs_etpu_data_ram_start)& 0x1FFF;
   *(pba + ((FS_ETPU_PMSMVC_PPIDQ_OFFSET          - 1)>>2)) = 
                         ((uint32_t)pba_pid_q - fs_etpu_data_ram_start)& 0x1FFF;
   *(pba + ((FS_ETPU_PMSMVC_UDCBUSACTUAL_OFFSET   - 1)>>2)) = 0;
   if(compensation_delay != 0)
   {
     *(pba + ((FS_ETPU_PMSMVC_COMPENSATIONDELAY_OFFSET -1)>>2)) = 
                                           compensation_delay;
     *((uint8_t*)pba + FS_ETPU_PMSMVC_OPTIONDELAYCOMP_OFFSET) = 
                                           FS_ETPU_PMSMVC_OPTION_DELAY_COMP_ON;
   }
   else
   {
     *((uint8_t*)pba + FS_ETPU_PMSMVC_OPTIONDELAYCOMP_OFFSET) = 
                                           FS_ETPU_PMSMVC_OPTION_DELAY_COMP_OFF;
   }
   *((uint8_t*)pba + FS_ETPU_PMSMVC_LINKCHAN_OFFSET) = (uint8_t)(link_chan+64);

   
   if(inv_mod_index==FS_ETPU_PMSMVC_INVMODINDEX_SINE)
      *(pba + ((FS_ETPU_PMSMVC_MODINDEX_OFFSET    - 1)>>2)) = 
                                              FS_ETPU_PMSMVC_MODINDEX_SINE;
   
   if((inv_mod_index==FS_ETPU_PMSMVC_INVMODINDEX_SIN3H)||
      (inv_mod_index==FS_ETPU_PMSMVC_INVMODINDEX_SVM))
      *(pba + ((FS_ETPU_PMSMVC_MODINDEX_OFFSET    - 1)>>2)) = 
                                              FS_ETPU_PMSMVC_MODINDEX_SVM;
   
   /* write PID D structure */
   /* proportional and integral portions are always calculated */
   pid_options_d = FS_ETPU_MC_CTRL_PID_P_GAIN | FS_ETPU_MC_CTRL_PID_I_GAIN;
   /* derivative portion is optional */
   if (p_pid_d_params->D_gain != 0)
      pid_options_d |= FS_ETPU_MC_CTRL_PID_D_GAIN;

   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_PGAIN_OFFSET - 1)>>2)) =
                                              (uint32_t)p_pid_d_params->P_gain;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_IGAIN_OFFSET - 1)>>2)) =
                                              (uint32_t)p_pid_d_params->I_gain;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_DGAIN_OFFSET - 1)>>2)) =
                                              (uint32_t)p_pid_d_params->D_gain;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_LIMITPOS_OFFSET - 1)>>2)) =
                                    (uint32_t)p_pid_d_params->positive_limit>>1;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_LIMITNEG_OFFSET - 1)>>2)) =
                                    (uint32_t)p_pid_d_params->negative_limit>>1;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_IK1H_OFFSET - 1)>>2)) = 0;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_IK1L_OFFSET - 1)>>2)) = 0;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_ERRORK1_OFFSET - 1)>>2)) = 0;
   *((uint8_t*)pba_pid_d + FS_ETPU_MC_CTRL_PID_OPTIONS_OFFSET) = pid_options_d;
   *((uint8_t*)pba_pid_d + FS_ETPU_MC_CTRL_PID_FLAGS_OFFSET) = 0;

   /* write PID Q structure */
   /* proportional and integral portions are always calculated */
   pid_options_q = FS_ETPU_MC_CTRL_PID_P_GAIN | FS_ETPU_MC_CTRL_PID_I_GAIN;
   /* derivative portion is optional */
   if (p_pid_q_params->D_gain != 0)
      pid_options_q |= FS_ETPU_MC_CTRL_PID_D_GAIN;

   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_PGAIN_OFFSET - 1)>>2)) =
                                              (uint32_t)p_pid_q_params->P_gain;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_IGAIN_OFFSET - 1)>>2)) =
                                              (uint32_t)p_pid_q_params->I_gain;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_DGAIN_OFFSET - 1)>>2)) =
                                              (uint32_t)p_pid_q_params->D_gain;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_LIMITPOS_OFFSET - 1)>>2)) =
                                    (uint32_t)p_pid_q_params->positive_limit>>1;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_LIMITNEG_OFFSET - 1)>>2)) =
                                    (uint32_t)p_pid_q_params->negative_limit>>1;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_IK1H_OFFSET - 1)>>2)) = 0;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_IK1L_OFFSET - 1)>>2)) = 0;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_ERRORK1_OFFSET - 1)>>2)) = 0;
   *((uint8_t*)pba_pid_q + FS_ETPU_MC_CTRL_PID_OPTIONS_OFFSET) = pid_options_q;
   *((uint8_t*)pba_pid_q + FS_ETPU_MC_CTRL_PID_FLAGS_OFFSET) = 0;

   /***************************************
   * Write HSR.
   ***************************************/
   if(mode==FS_ETPU_PMSMVC_MASTER)
      eTPU->CHAN[channel].HSRR.R = FS_ETPU_PMSMVC_HSR_INIT_MASTER;
   else
      eTPU->CHAN[channel].HSRR.R = FS_ETPU_PMSMVC_HSR_INIT_SLAVE;

   /****************************************
    * Set channel priority and enable.
    ***************************************/
   fs_etpu_enable(channel, priority);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_update
*PURPOSE      : This function executes the PMSMVC update.
*INPUTS NOTES : This function has 1 parameter:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_update(uint8_t channel)
{
   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   fs_etpu_set_hsr(channel, FS_ETPU_PMSMVC_HSR_UPDATE);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_i_d_desired
*PURPOSE      : This function changes the value of D-component 
*               of desired phase currents in 2-phase orthogonal rotating 
*               reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*   i_d_desired   - D-component of desired phase currents in 2-phase orthogonal
*                   rotating reference frame, in range MIN24 to MAX24.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_i_d_desired(uint8_t  channel,
                                       fract24_t  i_d_desired)
{
   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   fs_etpu_set_chan_local_24(channel, FS_ETPU_PMSMVC_IDQDESIRED_OFFSET+1,
                             (uint24_t)i_d_desired);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_i_q_desired
*PURPOSE      : This function changes the value of Q-component 
*               of desired phase currents in 2-phase orthogonal rotating 
*               reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*   i_q_desired   - Q-component of desired phase currents in 2-phase orthogonal
*                   rotating reference frame, in range MIN24 to MAX24.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_i_q_desired(uint8_t  channel,
                                       fract24_t  i_q_desired)
{
   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   fs_etpu_set_chan_local_24(channel, FS_ETPU_PMSMVC_IDQDESIRED_OFFSET+5,
                             (uint24_t)i_q_desired);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_i_dq_desired
*PURPOSE      : This function changes the desired values of phase currents 
                in 2-phase orthogonal rotating reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*   p_i_dq_desired- pointer to structure of desired phase currents in 2-phase
*                   orthogonal rotating reference frame,in range MIN24 to MAX24.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_i_dq_desired(uint8_t  channel,
                                        pmsmvc_dq_t * p_i_dq_desired)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   pba = fs_etpu_data_ram(channel);
   *(pba + ((FS_ETPU_PMSMVC_IDQDESIRED_OFFSET    )>>2)) = 
                                                  (uint32_t)(p_i_dq_desired->d);
   *(pba + ((FS_ETPU_PMSMVC_IDQDESIRED_OFFSET + 4)>>2)) = 
                                                  (uint32_t)(p_i_dq_desired->q);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_u_dc_bus_measured
*PURPOSE      : This function sets the value of actual DC-bus voltage,
*               as a portion of the AD convertor range.
*               This function can be used in case a DMA transfer of the value
*               from AD converter to eTPU is not used.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*  u_dc_bus_measured  - This is the actual value of DC-bus voltage, as unsigned
*                       24 bit portion of the AD convertor range.                       
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_u_dc_bus_measured(uint8_t  channel,
                                           ufract24_t  u_dc_bus_measured)
{
   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   fs_etpu_set_chan_local_24(channel, FS_ETPU_PMSMVC_UDCBUSACTUAL_OFFSET,
                             (uint24_t)u_dc_bus_measured);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_i_abc
*PURPOSE      : This function sets the values of i_abc - input phase currents 
*               in 3-phase stationary reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_i_abc           - phase currents in 3-phase stationary reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_i_abc(uint8_t  channel,
                                 pmsmvc_abc_t * p_i_abc)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel);
   *(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET    )>>2)) = (uint32_t)(p_i_abc->a);
   *(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET + 4)>>2)) = (uint32_t)(p_i_abc->b);
   *(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET + 8)>>2)) = (uint32_t)(p_i_abc->c);

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_i_abc
*PURPOSE      : This function gets the values of i_abc - input phase currents 
*               in 3-phase stationary reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_i_abc           - pointer to return structure of phase currents 
*                       in 3-phase stationary reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_i_abc(uint8_t  channel,
                                 pmsmvc_abc_t * p_i_abc)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_i_abc->a = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET    )>>2)));
   p_i_abc->b = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET + 4)>>2)));
   p_i_abc->c = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IABC_OFFSET + 8)>>2)));

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_i_ab
*PURPOSE      : This function gets the values of i_ab - phase currents 
*               in 2-phase orthogonal stationary reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_i_ab            - pointer to return structure of phase currents 
*                       in 2-phase orthogonal stationary reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_i_ab(uint8_t channel,
                                pmsmvc_ab_t * p_i_ab)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_i_ab->a = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IAB_OFFSET    )>>2)));
   p_i_ab->b = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IAB_OFFSET + 4)>>2)));

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_i_dq
*PURPOSE      : This function gets the values of i_dq - phase currents 
*               in 2-phase orthogonal rotating reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_i_dq            - pointer to return structure of phase currents 
*                       in 2-phase orthogonal rotating reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_i_dq(uint8_t channel,
                                pmsmvc_dq_t * p_i_dq)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_i_dq->d = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IDQ_OFFSET    )>>2)));
   p_i_dq->q = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IDQ_OFFSET + 4)>>2)));

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_i_dq_desired
*PURPOSE      : This function gets the values of i_dq_desired - desired phase 
*               currents in 2-phase orthogonal rotating reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_i_dq_desired    - pointer to return structure of phase currents 
*                       in 2-phase orthogonal rotating reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_i_dq_desired(uint8_t channel,
                                        pmsmvc_dq_t * p_i_dq_desired)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_i_dq_desired->d = 
     (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IDQDESIRED_OFFSET    )>>2)));
   p_i_dq_desired->q = 
     (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_IDQDESIRED_OFFSET + 4)>>2)));

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_u_dq
*PURPOSE      : This function gets the values of u_dq - stator voltages 
*               in 2-phase orthogonal rotating reference frame - before
*               circle limitation.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_u_dq            - pointer to return structure of stator voltages 
*                       in 2-phase orthogonal rotating reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_u_dq(uint8_t channel,
                                pmsmvc_dq_t * p_u_dq)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_u_dq->d = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_UDQ_OFFSET    )>>2))) << 2;
   p_u_dq->q = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_UDQ_OFFSET + 4)>>2))) << 2;

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_u_dq_clim
*PURPOSE      : This function gets the values of u_dq_clim - stator voltages 
*               in 2-phase orthogonal rotating reference frame - after circle
*               limitation.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_u_dq            - pointer to return structure of stator voltages 
*                       in 2-phase orthogonal rotating reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_u_dq_clim(uint8_t channel,
                                     pmsmvc_dq_t * p_u_dq)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_u_dq->d = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_UDQCLIM_OFFSET    )>>2))) << 2;
   p_u_dq->q = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_UDQCLIM_OFFSET + 4)>>2))) << 2;

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_u_ab
*PURPOSE      : This function gets the values of u_ab - stator voltages 
*               in 2-phase orthogonal stationary reference frame.
*INPUTS NOTES : This function has 2 parameters:
*   channel           - This is the PMSMVC channel number.
*                       This parameter must be assigned the same value
*                       as the channel parameter of the initialization
*                       function was assigned.
*   p_u_ab            - pointer to return structure of stator voltages 
*                       in 2-phase orthogonal stationary reference frame.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_get_u_ab(uint8_t channel,
                                pmsmvc_ab_t * p_u_ab)
{
   uint32_t * pba;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif
   
   pba = fs_etpu_data_ram(channel) + (0x4000>>2);
   p_u_ab->a = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_UAB_OFFSET    )>>2))) << 2;
   p_u_ab->b = (fract24_t)(*(pba + ((FS_ETPU_PMSMVC_UAB_OFFSET + 4)>>2))) << 2;

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_saturation_flag_d
*PURPOSE      : This function returns the PID controller saturation flags.
*INPUTS NOTES : This function has 1 parameter:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*
*RETURNS NOTES: This function returns saturation flags. The returned value
*               can be one of:
*               FS_ETPU_PMSMVC_SATURATION_NO  (0)...no saturation
*               FS_ETPU_PMSMVC_SATURATION_POS (1)...saturation to positive limit
*               FS_ETPU_PMSMVC_SATURATION_NEG (2)...saturation to negative limit
*******************************************************************************/
uint8_t fs_etpu_pmsmvc_get_saturation_flag_d(uint8_t channel)
{
   uint32_t * pba_pid;
   uint8_t flag;

   /* get PID structure address */
   pba_pid = (uint32_t*)(fs_etpu_data_ram_start +
             fs_etpu_get_chan_local_24(channel, FS_ETPU_PMSMVC_PPIDD_OFFSET));

   /* read from PID structure */
   flag = *((uint8_t*)pba_pid + FS_ETPU_MC_CTRL_PID_FLAGS_OFFSET);

   return(flag);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_get_saturation_flag_q
*PURPOSE      : This function returns the PID controller saturation flags.
*INPUTS NOTES : This function has 1 parameter:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*
*RETURNS NOTES: This function returns saturation flags. The returned value
*               can be one of:
*               FS_ETPU_PMSMVC_SATURATION_NO  (0)...no saturation
*               FS_ETPU_PMSMVC_SATURATION_POS (1)...saturation to positive limit
*               FS_ETPU_PMSMVC_SATURATION_NEG (2)...saturation to negative limit
*******************************************************************************/
uint8_t fs_etpu_pmsmvc_get_saturation_flag_q(uint8_t channel)
{
   uint32_t * pba_pid;
   uint8_t flag;

   /* get PID structure address */
   pba_pid = (uint32_t*)(fs_etpu_data_ram_start +
             fs_etpu_get_chan_local_24(channel, FS_ETPU_PMSMVC_PPIDQ_OFFSET));

   /* read from PID structure */
   flag = *((uint8_t*)pba_pid + FS_ETPU_MC_CTRL_PID_FLAGS_OFFSET);

   return(flag);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_integral_portion_d
*PURPOSE      : This function sets the integral portion of PID_D.
*INPUTS NOTES : This function has 2 parameters:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*   i_k1          - This is the integral portion value.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_integral_portion_d( uint8_t channel, fract24_t i_k1)
{
   fract24_t ik1h;
   fract24_t ik1l;
   uint32_t * pba_pid_d;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   if (i_k1 & 0x800000)
      i_k1 |= 0xFF000000;
   
   ik1h = i_k1 >> 9;
   ik1l = i_k1 << 15;

   /* get PID structure address */
   pba_pid_d = (uint32_t*)(fs_etpu_data_ram_start +
               fs_etpu_get_chan_local_24(channel, FS_ETPU_PMSMVC_PPIDD_OFFSET));

   /* write to PID structure */
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_IK1H_OFFSET - 1)>>2)) = (uint24_t)ik1h;
   *(pba_pid_d + ((FS_ETPU_MC_CTRL_PID_IK1L_OFFSET - 1)>>2)) = (uint24_t)ik1l;

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_integral_portion_q
*PURPOSE      : This function sets the integral portion of PID_Q.
*INPUTS NOTES : This function has 2 parameters:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*   i_k1          - This is the integral portion value.
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_integral_portion_q( uint8_t channel, fract24_t i_k1)
{
   fract24_t ik1h;
   fract24_t ik1l;
   uint32_t * pba_pid_q;

   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   if (i_k1 & 0x800000)
      i_k1 |= 0xFF000000;
   
   ik1h = i_k1 >> 9;
   ik1l = i_k1 << 15;

   /* get PID structure address */
   pba_pid_q = (uint32_t*)(fs_etpu_data_ram_start +
               fs_etpu_get_chan_local_24(channel, FS_ETPU_PMSMVC_PPIDQ_OFFSET));

   /* write to PID structure */
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_IK1H_OFFSET - 1)>>2)) = (uint24_t)ik1h;
   *(pba_pid_q + ((FS_ETPU_MC_CTRL_PID_IK1L_OFFSET - 1)>>2)) = (uint24_t)ik1l;

   return(0);
}

/*******************************************************************************
*FUNCTION     : fs_etpu_pmsmvc_set_configuration
*PURPOSE      : This function changes the PMSMVC configuration.
*INPUTS NOTES : This function has 2 parameters:
*   channel       - This is the PMSMVC channel number.
*                   This parameter must be assigned the same value
*                   as the channel parameter of the initialization
*                   function was assigned.
*   configuration - This is the required configuration of PMSMVC.
*                   This parameter should be assigned a value of:
*                   FS_ETPU_PMSMVC_PID_OFF or
*                   FS_ETPU_PMSMVC_PID_ON
*
*RETURNS NOTES: Error code that can be returned is: FS_ETPU_ERROR_VALUE.
*******************************************************************************/
int32_t fs_etpu_pmsmvc_set_configuration(uint8_t  channel,uint8_t configuration)
{
   /* Parameters bounds check */
   #ifdef FS_ETPU_MC_PARAM_CHECK
       if(((channel>31)&&(channel<64))||(channel>95)||
           (configuration>FS_ETPU_PMSMVC_PID_ON))
       {
          return(FS_ETPU_ERROR_VALUE);
       }
   #endif

   eTPU->CHAN[channel].SCR.B.FM0 = configuration;

   return(0);
}


/*********************************************************************
 *
 * Copyright:
 *	Freescale Semiconductor, INC. All Rights Reserved.
 *  You are hereby granted a copyright license to use, modify, and
 *  distribute the SOFTWARE so long as this entire notice is
 *  retained without alteration in any modified and/or redistributed
 *  versions, and that such modified versions are clearly identified
 *  as such. No licenses are granted by implication, estoppel or
 *  otherwise under any patents or trademarks of Freescale
 *  Semiconductor, Inc. This software is provided on an "AS IS"
 *  basis and without warranty.
 *
 *  To the maximum extent permitted by applicable law, Freescale
 *  Semiconductor DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
 *  INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
 *  PARTICULAR PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
 *  REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
 *  AND ANY ACCOMPANYING WRITTEN MATERIALS.
 *
 *  To the maximum extent permitted by applicable law, IN NO EVENT
 *  SHALL Freescale Semiconductor BE LIABLE FOR ANY DAMAGES WHATSOEVER
 *  (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
 *  BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER
 *  PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
 *
 *  Freescale Semiconductor assumes no responsibility for the
 *  maintenance and support of this software
 ********************************************************************/
