/*******************************************************************************
* Freescale Semiconductor Inc.
* (c) Copyright 2014 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
********************************************************************************
Services performed by FREESCALE in this matter are performed AS IS and without
any warranty. CUSTOMER retains the final decision relative to the total design
and functionality of the end product. FREESCALE neither guarantees nor will be
held liable by CUSTOMER for the success of this project.
FREESCALE DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING,
BUT NOT LIMITED TO, IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE ORE ADVISE SUPPLIED 
TO THE PROJECT BY FREESCALE, AND OR NAY PRODUCT RESULTING FROM FREESCALE 
SERVICES. IN NO EVENT SHALL FREESCALE BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL 
DAMAGES ARISING OUT OF THIS AGREEMENT.
CUSTOMER agrees to hold FREESCALE harmless against any and all claims demands 
or actions by anyone on account of any damage, or injury, whether commercial,
contractual, or tortuous, rising directly or indirectly as a result 
of the advise or assistance supplied CUSTOMER in connection with product, 
services or goods supplied under this Agreement.
********************************************************************************
* File:             uart.c
* Owner:            b05111
* Version:          0.0
* Date:             Jul-01-2014
* Classification:   General Business Information
* Brief:            terminal IO. implements CodeWarrior MSL library calls
*                   MSL_C library printf() output to MPC5643L's LINFlex0
********************************************************************************
* Detailed Description: 
* 
* implements CW MSL library function calls to implement printf() on LINFlex0
* header file UART.h is taken from the CW as is
* global functions defined in this module replace the ones from the library
* so finally we send printf() to LINFlex0
*
* ------------------------------------------------------------------------------
* Test HW:  MPC5675KEVB, PPC5675KFMMSA 0N72D
* Target :  internal_FLASH, RAM
* Fsys:     180 MHz PLL0
* Debugger: Lauterbach Trace32. script for internal_FLASH run_from_flash.cmm
*                               script for RAM: run_from_run_vle_lsm
*
********************************************************************************
Revision History:
1.0     Jul-01-2014     b05111  Initial Version
*******************************************************************************/

#include "MPC5675K.h"
#include "uart.h"
#include "clock.h"

/*******************************************************************************
* Global variables
*******************************************************************************/

/*******************************************************************************
* Constants and macros
*******************************************************************************/

/*******************************************************************************
* Local types
*******************************************************************************/

/*******************************************************************************
* Local function prototypes
*******************************************************************************/
static void Init_LINFlex_0(void);
static void TransmitData(const char * pBuf, const uint32_t cnt);
static int32_t ReceiveData(char * const pBuf);

/*******************************************************************************
* Local variables
*******************************************************************************/

/*******************************************************************************
* Local functions
*******************************************************************************/ 

/*******************************************************************************
Function Name : Init_LINFlex_0
Engineer      : b05111
Date          : Nov-10-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : initializes MPC5675K's Init_LINFlex_0 module for UART mode
Issues        : expecting PERI1_CLK clock is 45/37.5MHz what means 
                  - SYS_CLK = 180/150MHz
                  - NVUSRO[CR] = 3 => 1:2 mode (default)
                  - CGM_SC_DC1 = 0x81  => divide by 2

*******************************************************************************/
static void Init_LINFlex_0 (void)
{
	/* enter INIT mode */
	LINFLEX_0.LINCR1.R = 0x0081; /* SLEEP=0, INIT=1 */
	//LINFLEX_0.LINCR1.R = 0x0001;
	
	/* wait for the INIT mode */
	while (0x1000 != (LINFLEX_0.LINSR.R & 0xF000)) {}
		
	/* configure pads */
	SIU.PCR[18].R = 0x0604;     /* Configure pad PB2 for AF1 func: LIN0TX */
	SIU.PCR[19].R = 0x0100;     /* Configure pad PB3 for LIN0RX */	
	
	/* configure for UART mode */
	/* set the UART bit first to be able to write the other bits */
	LINFLEX_0.UARTCR.R = 0x0001; 
	
	/* 8bit data, no parity, Tx and Rx enabled, UART mode */
	/* Transmit buffer size  1 (TDFL = 0), Receive buffer size = 1 (RDFL = 0)*/
	LINFLEX_0.UARTCR.R = 0x0033; 							 
	
	/* LFDIV = fsys / (16 * desired baudrate)
	   LINFBRR = 16 * fractional part of LFDIV (after decimal point)
	   LINIBRR = integer part of LFDIV	   
	    
	   for instance:
	   LFDIV = 45e6/(16*19200) = 146.484375
	   LINFBRR = 16*0.484375 = 7.75 => 8
	   LINIBRR = 146
	   
	   or
	   
	   LFDIV = 37.5e6/(16*19200) = 122.0703125
	   LINFBRR = 16*0.0703125 = 1.125 => 1
	   LINIBRR = 122   
	   
	   NOTE: LINFBRR must be written before LINIBRR !!!	   
	*/
    
    /* assuming 180 MHz */
    
	#if defined(CORE_CLOCK_180MHz)	
    	LINFLEX_0.LINFBRR.R = 8;
    	LINFLEX_0.LINIBRR.R = 146;
    	
    /* assuming 150 MHz */
	#elif defined(CORE_CLOCK_150MHz)
    	LINFLEX_0.LINFBRR.R = 1;
    	LINFLEX_0.LINIBRR.R = 122;	
	#else
	/* PLL unitialized */
	#endif
		
	/* enter NORMAL mode */
	LINFLEX_0.LINCR1.R = 0x0080; /* INIT=0 */
}


/*******************************************************************************
Function Name : TransmitData
Engineer      : b05111
Date          : Apr-14-2011
Parameters    : pBuf - input string. won't be modified by the function
              : cnt  - input number of characters to be transmitted
Modifies      : 
Returns       : 
Notes         : Tx data on LINFlex_0. polled mode. 
Issues        :  
*******************************************************************************/
static void TransmitData(const char * const pBuf, const uint32_t cnt) 
{
    uint32_t	j = 0; // Dummy variable
    
    for (j=0; j< cnt; j++) 
    {  // Loop for character string  
   	    LINFLEX_0.BDRL.B.DATA0 = *(pBuf+j);    
   	      //write character to transmit buffer
	    while (1 != LINFLEX_0.UARTSR.B.DTFTFF) {}
	      // Wait for data transmission completed flag
	    LINFLEX_0.UARTSR.R = 0x0002;
	      // clear the DTF flag and not the other flags
    }

    
}

/*******************************************************************************
Function Name : ReceiveData
Engineer      : b05111
Date          : Sep-12-2112
Parameters    : pBuf - address of a char where the received char is written to
                       the address (pBuf) doesn't change in the function
Modifies      : 
Returns       : 
Notes         : Rx data on LINFlex_0. polled mode. 
Issues        :  
*******************************************************************************/
static int32_t ReceiveData(char * const pBuf) 
{
    
    int32_t rx_data;
    
    /* wait for DRF */
	while (1 != LINFLEX_0.UARTSR.B.DRFRFE) {}  /* Wait for data reception completed flag */
		
	/* wait for RMB */
	while (1 != LINFLEX_0.UARTSR.B.RMB) {}  /* Wait for Release Message Buffer */
	
	/* get the data */
	
	rx_data = LINFLEX_0.BDRM.R; // read whole register due to erratum e4897PS
    
	*pBuf = (uint8_t)rx_data; // take received data and place to t 
	
	/* clear the DRF and RMB flags by writing 1 to them */
	LINFLEX_0.UARTSR.R = 0x0204;
    
    return kUARTNoError;
}


/*******************************************************************************
* Global functions
*******************************************************************************/ 

/*
Methods called by MW MSL libraries to perform console IO:
*/

UARTError ReadUARTPoll(char* c) 
{
    int32_t rx_data;
    
    rx_data = LINFLEX_0.BDRM.R; // read whole register due to erratum e4897PS
    
    if (LINFLEX_0.UARTSR.B.RMB == 0)
        return  kUARTNoData;  // return no data  
    else 
    {
        LINFLEX_0.UARTSR.R = 0x0204;
        *c =(unsigned char) rx_data; // read byte of Data
        return kUARTNoError;  // return no error
    }  
}


UARTError InitializeUART(UARTBaudRate baudRate)
{	
#pragma unused(baudRate)
	Init_LINFlex_0 ();  
	return kUARTNoError; 
}


UARTError ReadUARTN(void* bytes, unsigned long limit)
{
	int count;
	UARTError err; 

	for (count = 0, err = kUARTNoError; 
		count < limit && err == kUARTNoError;
		count++)
        {
		err = ReceiveData( (char *)bytes + count );
        }

	return err;
}


UARTError WriteUARTN(const void * bytes, unsigned long length)
{ 
	TransmitData ((const char * const)bytes,length);  
  	return kUARTNoError; 
}
