/** @file dig_inputs.c
 
   Contains all functions to manage timer / watchdog of the APCIE-2200.
 
   @par CREATION  
   @author Krauth Julien
   @date   28.01.2010
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
   
   @par LICENCE
   @verbatim
   Copyright (C) 2009  ADDI-DATA GmbH for the source code of this module.
        
        ADDI-DATA GmbH
        Airpark Business Center
        Airport Boulevard B210
        77836 Rheinmuenster
        Germany
        Tel: +49(0)7229/1847-0
        Fax: +49(0)7229/1847-200
        http://www.addi-data-com
        info@addi-data.com
        
   This program is free software; you can redistribute it and/or modify it under 
   the terms of the GNU General Public License as published by the Free Software 
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, 
   but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
   or FITNESS FOR A PARTICULAR PURPOSE. 
   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along with 
   this program; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

   You shoud also find the complete GPL in the COPYING file 
   accompanying this source code.
   @endverbatim   
 */

#include <apcie2200-kapi.h>
#include "apcie2200-private.h"
#include "tcw.h"

/**@def EXPORT_NO_SYMBOLS
 * Function in this file are not exported.
 */
EXPORT_NO_SYMBOLS;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
	#define __user 
#endif

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

/** Configure the timer / watchdog
 *
 * @param [in] pdev: Device to manage.
 *
 * @param [in] ressourceType:	0: Watchdog
 *								1: Timer
 *
 * @param [in] mode: At this time only mode 2 is available (value 2).
 *
 * @param [in] timeBaseUnit: Unit for the time base.
 * 							us: 1
 *							ms: 2
 *							s:  3
 *
 * @param [in] timeBaseValue: Timer / Watchdog reload value.
 * 								12 Bit for Watchdog.
 * 								16 Bit for Timer.
 *
 * @param [in] irq: 1: Enable interrupt
 * 					0: Disable interrupt
 *
 * @retval 0: No error.
 * @retval -EINVAL: Error.
 */
int APCIE2200_TimerWatchdogInitAndStart(struct pci_dev *pdev, uint32_t ressourceType, uint32_t mode, uint32_t timeBaseUnit, uint32_t timeBaseValue, uint32_t irq)
{
	uint32_t timerOffset = 0;

	/* check parameters */
	if (!pdev)
		return -EINVAL;

	if ((ressourceType > 1) || (ressourceType < 0))
		return -EINVAL;

	if ((timeBaseUnit > 3) || (timeBaseUnit < 1))
		return -EINVAL;

	if (timeBaseValue == 0)
		return -EINVAL;

	if ((ressourceType == 0) && (timeBaseValue > 0xFFF))
		return -EINVAL;

	if ((ressourceType == 1) && (timeBaseValue > 0xFFFF))
		return -EINVAL;

	if ((irq > 1) || (irq < 0))
		return -EINVAL;

	/* Mode always 2 */
	mode = 2;

	/* Set offsets */
	switch (ressourceType)
	{
		case 0:
			timerOffset = APCIE2200_TIMER0_OFFSET;
		break;

		case 1:
			timerOffset = APCIE2200_TIMER1_OFFSET;
		break;
	}

	/* Perform configuration */
	{
		/* Release all */
		tcw_set_control_register (GET_BAR3(pdev) + timerOffset, 0);

		tcw_set_reload_value (GET_BAR3(pdev) + timerOffset, timeBaseValue);

		tcw_set_time_base (GET_BAR3(pdev) + timerOffset, timeBaseUnit);

		/* Mode 2: (mode << 13) | Watchdog or Timer: (0 << 4) | Enable / Disable IRQ: (irq << 1) | Start the timer: 0 */
		tcw_set_control_register (GET_BAR3(pdev) + timerOffset, ((mode << 13) | (0 << 4) | (irq << 1) | 1));
	}

	return 0;
}

//------------------------------------------------------------------------------

/** Release the timer / watchdog
 *
 * @param [in] pdev: Device to manage.
 *
 * @param [in] ressourceType:	0: Watchdog
 *								1: Timer
 *
 * @retval 0: No error.
 * @retval -EINVAL: Error.
 */
int APCIE2200_TimerWatchdogStopAndRelease (struct pci_dev *pdev, uint32_t ressourceType)
{
	uint32_t timerOffset = 0;

	/* check parameters */
	if (!pdev)
		return -EINVAL;

	if ((ressourceType > 1) || (ressourceType < 0))
		return -EINVAL;

	switch (ressourceType)
	{
		case 0:
			timerOffset = APCIE2200_TIMER0_OFFSET;
		break;

		case 1:
			timerOffset = APCIE2200_TIMER1_OFFSET;
		break;
	}

	/* Release all */
	tcw_set_control_register (GET_BAR3(pdev) + timerOffset, 0);

	return 0;
}

//------------------------------------------------------------------------------

/** Trigger the timer / watchdog
 *
 * @param [in] pdev: Device to manage.
 *
 * @param [in] ressourceType:	0: Watchdog
 *								1: Timer
 *
 * @retval 0: No error.
 * @retval -EINVAL: Error.
 */
int APCIE2200_TimerWatchdogTrigger (struct pci_dev *pdev, uint32_t ressourceType)
{
	uint32_t timerOffset = 0;

	/* check parameters */
	if (!pdev)
		return -EINVAL;

	if ((ressourceType > 1) || (ressourceType < 0))
		return -EINVAL;

	switch (ressourceType)
	{
		case 0:
			timerOffset = APCIE2200_TIMER0_OFFSET;
		break;

		case 1:
			timerOffset = APCIE2200_TIMER1_OFFSET;
		break;
	}

	tcw_trigger (GET_BAR3(pdev) + timerOffset);

	return 0;
}

//------------------------------------------------------------------------------

/** Read the timer / watchdog value
 *
 * @param [in] pdev: Device to manage.
 *
 * @param [in] ressourceType:	0: Watchdog
 *								1: Timer
 *
 * @param [out] Value: Read value.
 *
 * @retval 0: No error.
 * @retval -EINVAL: Error.
 */
int APCIE2200_TimerWatchdogRead (struct pci_dev *pdev, uint32_t ressourceType, uint32_t *value)
{
	uint32_t timerOffset = 0;

	/* check parameters */
	if (!pdev)
		return -EINVAL;

	if ((ressourceType > 1) || (ressourceType < 0))
		return -EINVAL;

	switch (ressourceType)
	{
		case 0:
			timerOffset = APCIE2200_TIMER0_OFFSET;
		break;

		case 1:
			timerOffset = APCIE2200_TIMER1_OFFSET;
		break;
	}

	*value = tcw_read_value (GET_BAR3(pdev) + timerOffset);

	return 0;
}

//------------------------------------------------------------------------------

/** Get the timer / watchdog status
 *
 * @param [in] pdev: Device to manage.
 *
 * @param [in] ressourceType:	0: Watchdog
 *								1: Timer
 *
 * @param [out] status: D[0]: 1: Timer overflow
 * 						D[1]: 1: Software trigger
 *
 * @retval 0: No error.
 * @retval -EINVAL: Error.
 */
int APCIE2200_TimerWatchdogGetStatus (struct pci_dev *pdev, uint32_t ressourceType, uint32_t *status)
{
	uint32_t timerOffset = 0;

	/* check parameters */
	if (!pdev)
		return -EINVAL;

	if ((ressourceType > 1) || (ressourceType < 0))
		return -EINVAL;

	switch (ressourceType)
	{
		case 0:
			timerOffset = APCIE2200_TIMER0_OFFSET;
		break;

		case 1:
			timerOffset = APCIE2200_TIMER1_OFFSET;
		break;
	}

	*status = tcw_get_status (GET_BAR3(pdev) + timerOffset);

	return 0;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
