/* $Id$ */
/******************************************************************************
*
* (c) Copyright 2012 Xilinx, Inc. All rights reserved.
*
* This file contains confidential and proprietary information of Xilinx, Inc.
* and is protected under U.S. and international copyright and other
* intellectual property laws.
*
* DISCLAIMER
* This disclaimer is not a license and does not grant any rights to the
* materials distributed herewith. Except as otherwise provided in a valid
* license issued to you by Xilinx, and to the maximum extent permitted by
* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
* and (2) Xilinx shall not be liable (whether in contract or tort, including
* negligence, or under any other theory of liability) for any loss or damage
* of any kind or nature related to, arising under or in connection with these
* materials, including for any direct, or any indirect, special, incidental,
* or consequential loss or damage (including loss of data, profits, goodwill,
* or any type of loss or damage suffered as a result of any action brought by
* a third party) even if such damage or loss was reasonably foreseeable or
* Xilinx had been advised of the possibility of the same.
*
* CRITICAL APPLICATIONS
* Xilinx products are not designed or intended to be fail-safe, or for use in
* any application requiring fail-safe performance, such as life-support or
* safety devices or systems, Class III medical devices, nuclear facilities,
* applications related to the deployment of airbags, or any other applications
* that could lead to death, personal injury, or severe property or
* environmental damage (individually and collectively, "Critical
* Applications"). Customer assumes the sole risk and liability of any use of
* Xilinx products in Critical Applications, subject only to applicable laws
* and regulations governing limitations on product liability.
*
* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
* AT ALL TIMES.
*
******************************************************************************/

/****************************************************************************/
/**
*
* @file xiomodule_uart.c
*
* Contains required functions for the XIOModule UART driver. See the
* xiomodule.h header file for more details on this driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.02a sa   07/25/12 First release
* 1.03a sa   10/16/12 Moved interrupt mode functions to separate file
* </pre>
*
*****************************************************************************/

/***************************** Include Files ********************************/

#include "xil_assert.h"
#include "xiomodule.h"
#include "xiomodule_i.h"
#include "xiomodule_l.h"

/************************** Constant Definitions ****************************/

/* The following constant defines the amount of error that is allowed for
 * a specified baud rate. This error is the difference between the actual
 * baud rate that will be generated using the specified clock and the
 * desired baud rate.
 */
#define XUN_MAX_BAUD_ERROR_RATE		3	 /* max % error allowed */

/**************************** Type Definitions ******************************/


/***************** Macros (Inline Functions) Definitions ********************/


/************************** Function Prototypes *****************************/

static void StubHandler(void *CallBackRef, unsigned int ByteCount);

/************************** Variable Definitions ****************************/


/****************************************************************************/
/**
*
* Initialize a XIOModule instance. This function disables the UART
* interrupts. The baud rate and format of the data are fixed in the hardware
* at hardware build time, except if programmable baud rate is selected.
*
* @param	InstancePtr is a pointer to the XIOModule instance.
* @param	Config is a reference to a structure containing information
*		about a specific IO Module device. This function initializes an
*		InstancePtr object for a specific device specified by the
*		contents of Config. This function can initialize multiple
*		instance objects with the use of multiple calls giving different
*		Config information on each call.
* @param 	EffectiveAddr is the device register base address. Use
*		Config->BaseAddress for this parameters, passing the physical
*		address.
*
* @return
* 		- XST_SUCCESS if everything starts up as expected.
*
* @note		The Config and EffectiveAddress arguments are not used by this
*		function, but are provided to keep the function signature
*		consistent with other drivers.
*
*****************************************************************************/
int XIOModule_CfgInitialize(XIOModule *InstancePtr, XIOModule_Config *Config,
				u32 EffectiveAddr)
{
	u32 NewIER;

	/*
	 * Assert validates the input arguments
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);

	/*
	 * Set some default values, including setting the callback
	 * handlers to stubs.
	 */
	InstancePtr->SendBuffer.NextBytePtr = NULL;
	InstancePtr->SendBuffer.RemainingBytes = 0;
	InstancePtr->SendBuffer.RequestedBytes = 0;

	InstancePtr->ReceiveBuffer.NextBytePtr = NULL;
	InstancePtr->ReceiveBuffer.RemainingBytes = 0;
	InstancePtr->ReceiveBuffer.RequestedBytes = 0;

	InstancePtr->IsReady = XIL_COMPONENT_IS_READY;

	InstancePtr->RecvHandler = StubHandler;
	InstancePtr->SendHandler = StubHandler;

	/* 
	 * Modify the IER to disable the UART interrupts
	 */
	NewIER = InstancePtr->CurrentIER & 0xFFFFFFF8;
	XIomodule_Out32(InstancePtr->BaseAddress + XIN_IER_OFFSET, NewIER);
	InstancePtr->CurrentIER = NewIER;

	/*
	 * Clear the statistics for this driver
	 */
	XIOModule_ClearStats(InstancePtr);

	return XST_SUCCESS;
}

/****************************************************************************
*
* Sets the baud rate for the specified UART. Checks the input value for
* validity and also verifies that the requested rate can be configured to
* within the 3 percent error range for RS-232 communications. If the provided
* rate is not valid, the current setting is unchanged.
*
* This function is designed to be an internal function only used within the
* XIOModule component. It is necessary for initialization and for the user
* available function that sets the data format.
*
* @param	InstancePtr is a pointer to the XIOModule instance.
* @param	BaudRate to be set in the hardware.
*
* @return
*		- XST_SUCCESS if everything configures as expected
* 		- XST_UART_BAUD_ERROR if the requested rate is not available
*		because there was too much error due to the input clock
*
* @note		None.
*
*****************************************************************************/
int XIOModule_SetBaudRate(XIOModule *InstancePtr, u32 BaudRate)
{
	u32 Baud8;
	u32 Baud16;
        u32 InputClockHz;
	u32 Divisor;
	u32 TargetRate;
	u32 Error;
	u32 PercentError;

	/*
	 * Assert validates the input arguments
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Determine what the divisor should be to get the specified baud
	 * rate based upon the input clock frequency and a baud clock prescaler
	 * of 16, rounded to nearest divisor
	 */
	Baud8 = BaudRate << 3;
	Baud16 = Baud8 << 1;
        InputClockHz = InstancePtr->CfgPtr->InputClockHz;
	Divisor = (InputClockHz + Baud8) / Baud16;

	/*
	 * Check for too much error between the baud rate that will be generated
	 * using the divisor and the expected baud rate, ensuring that the error
	 * is positive due to rounding above
	 */
	TargetRate = Divisor * Baud16;
	if (InputClockHz < TargetRate)
		Error = TargetRate - InputClockHz;
	else
		Error = InputClockHz - TargetRate;

	/*
	 * Error has total error now compute the percentage multiplied by 100 to
	 * avoid floating point calculations, should be less than 3% as per
	 * RS-232 spec
	 */
	PercentError = (Error * 100UL) / InputClockHz;
	if (PercentError > XUN_MAX_BAUD_ERROR_RATE) {
		return XST_UART_BAUD_ERROR;
	}

	/*
	 * Write the baud rate divisor to the UART Baud Rate Register
	 */
	XIOModule_WriteReg(InstancePtr->BaseAddress,
			   XUL_BAUDRATE_OFFSET,
			   Divisor - 1);
	InstancePtr->CurrentUBRR = Divisor - 1;

	/*
	 * Save the baud rate in the instance so that the get baud rate function
	 * won't have to calculate it from the divisor
	 */
	InstancePtr->CfgPtr->BaudRate = BaudRate;

	return XST_SUCCESS;
}

/****************************************************************************
*
* This function provides a stub handler such that if the application does not
* define a handler but enables interrupts, this function will be called.
*
* @param	CallBackRef has no purpose but is necessary to match the
*		interface for a handler.
* @param	ByteCount has no purpose but is necessary to match the
*		interface for a handler.
*
* @return	None.
*
* @note		None.
*
*****************************************************************************/
static void StubHandler(void *CallBackRef, unsigned int ByteCount)
{
	/*
	 * Assert occurs always since this is a stub and should never be called
	 */
	Xil_AssertVoidAlways();
}
