/* 2012-09-16: File added and changed by Sony Corporation */
/*
 * icx_adc.c
 *
 * Copyright 2011 Sony Corporation.
 *
 * 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
 *
 */

#include <common.h>

#if defined(CONFIG_ICX) || defined(CONFIG_ICD)

#include <asm/errno.h>

#include "icx_pwc.h"
#include "icx_adc.h"

/****************/
/*@ definitions */
/****************/

#define ADC_TIMEOUT            1000

#define PWC_DETMOD3L_ADINT_SFT    0
#define PWC_FACT_ADINT         0x01

#define PWC_ADRQ_STOP          0x00
#define PWC_ADRQ_SINGLE        0x10
#define PWC_ADRQ_MASK          0x70

#define PWC_ADSEL_MASK         0x07

/********************/
/*@ global routines */
/********************/

/*-----------------------------------------------------------------------------
 * Function	: adc_init
 * Abstruct : Initialize A/D convertor
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
void adc_init(void)
{
	/* setup interrupt det type 0:level 1:rise 2:fall */
	pwc_write(PWC_INTC_DETMOD3L,
			  (PWC_DETMOD_RISE << PWC_DETMOD3L_ADINT_SFT),
			  (PWC_DETMOD_MASK << PWC_DETMOD3L_ADINT_SFT));

	/* set front mask */
	pwc_write(PWC_INTC_FMASK3, PWC_FACT_ADINT, PWC_FACT_ADINT);
}

/*-----------------------------------------------------------------------------
 * Function	: adc_exit
 * Abstruct : Exit A/D convertor
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
void adc_exit(void)
{
	/* clear mask */
	pwc_write(PWC_INTC_FMASK3, 0x00, PWC_FACT_ADINT);

	/* clear interrupt factor */
	pwc_write(PWC_INTC_CLRFACT3, PWC_FACT_ADINT, PWC_FACT_ADINT);
}

/*-----------------------------------------------------------------------------
 * Function : adc_read
 * Abstruct : Read a value from A/D convertor
 * Input    : ch      : CH number(0-7)
 *          : data    : value
 * Return   : 0          : success
 *          : -EINVAL    : invalid parameter
 *          : -ETIMEDOUT : ADC timeout
 *----------------------------------------------------------------------------*/
int adc_read(int ch, unsigned int *data)
{
	unsigned char fact = 0;
	unsigned char val  = 0;
	int	   cnt;
	int    ret = 0;

	if (ch > ADC_CH_8)
		return -EINVAL;

	/* clear interrupt factor */
	pwc_write(PWC_INTC_CLRFACT3, PWC_FACT_ADINT, PWC_FACT_ADINT);

	/* start ADC */
	pwc_write(PWC_ADC_ADMODE,
			  (PWC_ADRQ_SINGLE | (ch & PWC_ADSEL_MASK)),
			  (PWC_ADRQ_MASK | PWC_ADSEL_MASK));

	/* wait for ADC completion */
	for (cnt = ADC_TIMEOUT; cnt > 0; cnt--) {
		ret = pwc_read(PWC_INTC_FACTOR3, &fact);
		if ((ret == 0) && (fact & PWC_FACT_ADINT))
			break;
	}

	/* read a value */
	if (cnt > 0)
		ret = pwc_read((PWC_ADC_ADDATA1 + (ch * 2)), &val);
	else 
		ret = -ETIMEDOUT;

	/* stop ADC */
	pwc_write(PWC_ADC_ADMODE,
			  (PWC_ADRQ_STOP | (ch & PWC_ADSEL_MASK)),
			  (PWC_ADRQ_MASK | PWC_ADSEL_MASK));

	*data = (unsigned int)val;

	return ret;
}

#endif	/* CONFIG_ICX || CONFIG_ICD */ 
