/* 2012-09-16: File added and changed by Sony Corporation */
/*
 * icx_pmu.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 "reg.h"
#include "icx_io.h"
#include "icx_pwc.h"
#include "icx_adc.h"
#include "icx_pmu.h"
#include "icx_rtc.h"


/****************/
/*@ Definitions */
/****************/

/* battery threshold */
#define BTT_LOW					183	/* 3.35V : 183 - 179 : low			*/
#define BTT_VERY_LOW			178	/* 3.25V : 178 -   0 : very low		*/
#define BTT_LOW_ALPHA			  3	/* +55mV : u-boot battery low alpha	*/

/* CHG_BOOT_MODE mask */
#define	CHG_BOOT_MODE_MASK		0x0000000E

/* sram address & magic */
#define BATTERY_FLAG_SAVE_ADDR  0xF0000100
#define BOOT_FACTOR1_SAVE_ADDR  0xF0000110
#define BOOT_FACTOR2_SAVE_ADDR  0xF0000114
#define BOOT_FACTOR3_SAVE_ADDR  0xF0000118
#define BOOT_WRSTFCT_SAVE_ADDR  0xF000011C
#define BATTERY_FLAG_SAVE_MAGIC	0x74420000	/* "Bt" */
#define BOOT_FACTOR1_SAVE_MAGIC 0x31460000	/* "F1" */
#define BOOT_FACTOR2_SAVE_MAGIC 0x32460000	/* "F2" */
#define BOOT_FACTOR3_SAVE_MAGIC 0x33460000	/* "F3" */
#define BOOT_WRSTFCT_SAVE_MAGIC 0x46520000	/* "RF" */
#define MAGIC_MASK              0xFFFF0000

/* boot factors shift */
#define BOOT_WRSTFCT_SHIFT		24
#define BOOT_FACTOR3_SHIFT		16
#define BOOT_FACTOR2_SHIFT		8
#define BOOT_FACTOR1_SHIFT		0

/* reset flag address & value */
#define RESET_FLAG_SAVE_ADDRESS	CONFIG_RESET_FLAG_ADDR
#define RESET_FLAG_SAVE_VALUE	0x744F6F42	/* "BoOt" */

/* battery A/D convert ch. */
#define VBAT_ADC_CH				ADC_CH_BATTERY

/* GIC reg value */
#define GIC_INT_MASK_ALL		0xFFFFFFFF

/* gpio reg value */
#define GIO_IDS_MASK_ALL		0xFFFFFFFF

/**************/
/*@ PMU macro */
/**************/

/* PMU parameters */
#define PMU_WDT_ENABLE					0x00000001
#define PMU_WDT_MAX_COUNT				0x0003FFFF
#define PMU_START_SET					0x00000001

/* PC <-> address */
#define PMU_VIRADDR_TO_PC(addr)			((unsigned int)addr - PMU_BASE)
#define PMU_PC_TO_VIRADDR(pc)			(unsigned int *)(pc + PMU_BASE)

/* for command sequence SMU register address */
#define SMU_CMD_PLL_STATUS				0x0234
#define SMU_CMD_CLK_MODE_SEL			0x0300
#define SMU_CMD_MEMC_HAND_SHAKE_FAKE	0x0304
#define SMU_CMD_CPUGCLKCTRL				0x0400
#define SMU_CMD_USIAS0GCLKCTRL			0x0498

#define SMU_CMD_POWER_STATUS			0x082C
#define SMU_CMD_SEQ_BUSY				0x0830
#define SMU_CMD_P0_SWON					0x0834
#define SMU_CMD_PU_SWON					0x083C
#define SMU_CMD_P1_SWON					0x084C
#define SMU_CMD_PG_SWON					0x0854
#define SMU_CMD_PV_SWON					0x0858
#define SMU_CMD_PR_SWON					0x085C
#define SMU_CMD_P0_PWSW_PARA			0x0868
#define SMU_CMD_PU_PWSW_PARA			0x0880
#define SMU_CMD_PD_PWSW_PARA			0x08A4
#define SMU_CMD_P1_PWSW_PARA			0x08B0
#define SMU_CMD_PG_PWSW_PARA			0x08C8
#define SMU_CMD_PR_PWSW_PARA			0x08E0
#define SMU_CMD_PV_PWSW_PARA			0x08D4

#define SMU_CMD_PMU_INTCTRL				0x0A30

/* for command sequence MEMC register address */
#define MEMC_CMD_MEMC_DDR_CONFIGC1		0x200c
#define MEMC_CMD_MEMC_DDR_CONFIGC2		0x2010
#define MEMC_CMD_MEMC_DDR_CONFIGR2		0x2018
#define MEMC_CMD_MEMC_DDR_CONFIGR3		0x201c
#define MEMC_CMD_MEMC_DDR_STATE8		0x202c

/* for command sequence SPI register address */
#define SIO_CMD_SP0_MODE				0x1000
#define SIO_CMD_SP0_POL					0x1004
#define SIO_CMD_SP0_CONTROL				0x1008
#define SIO_CMD_SP0_TX_DATA				0x1010
#define SIO_CMD_SP0_ENSET				0x1020
#define SIO_CMD_SP0_FFCLR				0x1028

/* for command sequence MEM register address */
#define MEMC_CMD_DDR_STATE8				0x202C

/* PMU PC */
#define PMU_PC_MAIN						0x1000			/* Normal2Economy */
#define PMU_PC_PWRCNT2					0x11C0
#define PMU_PC_ON1						0x1200
#define PMU_PC_ON2						0x12C0
#define PMU_PC_SUB_SWOFF0				0x1300
#define PMU_PC_SUB_SWOFF2				0x1400
#define PMU_PC_SUB_SWOFF3				0x14A0
#define PMU_PC_SUB_SWON0				0x1500
#define PMU_PC_SUB_SWON2				0x1750
#define PMU_PC_SUB_SWON3				0x1800
#define PMU_PC_SUB_SPI1					0x1940
#define PMU_PC_SUB_SPI2					0x1980
#define PMU_PC_SUB_SETPARA				0x1A00
#define PMU_PC_SUB_VDD_SPI				0x1F00

/* APB macro parameter */
#define MEMC_MACRO				(0x04 << 16)
#define PMU_MACRO				(0x09 << 16)
#define SMU_MACRO				(0x0A << 16)
#define SIO0_MACRO				(0x0B << 16)	/* USIA */

/* command parameters */
#define CMD_REG_WRITE			(0x00 << 24)
#define CMD_USI0_WRITE			(0x01 << 24)
#define CMD_REG_READ			(0x02 << 24)
#define CMD_RMW					(0x03 << 24)
#define CMD_AND					(0x05 << 24)
#define CMD_CMP2				(0x08 << 24)
#define CMD_REG_WRITE2			(0x09 << 24)
#define CMD_BRANCH				(0x10 << 24)
#define CMD_AJUMP				(0x12 << 24)
#define CMD_SUBROUTINE_START	(0x13 << 24)
#define CMD_RFS					(0x14 << 24)
#define CMD_INTWAIT				(0x21 << 24)
#define CMD_SMU_READY_WAIT		(0x23 << 24)
#define CMD_TRIG_WAIT			(0x24 << 24)
#define CMD_INT_MASK			(0x30 << 24)
#define CMD_WDT_STOP			(0x33 << 24)
#define CMD_WDT_RESTART			(0x34 << 24)
#define CMD_PMU_END				(0x35 << 24)
#define CMD_NOP					(0x36 << 24)	/* as Other value */

/* other parameters */
#define PMU_REGA				(0 << 30)
#define PMU_REGB				(1 << 30)
#define PMU_BEQ					(0 << 30)
#define PMU_BNE					(1 << 30)
#define PMU_HIGH_LEVEL			(1 << 30)
#define PMU_TRIG_P1WAKEUP_LOW	(1 << 19)
#define PMU_TRIG_INT			(1 << 21)
#define PMU_INT_MASK			(1 << 30)

/* PMU command size */
#define PCMD_BRANCH_SIZE		4
#define PCMD_RMW_SIZE			12
#define PCMD_REG_READ_SIZE		4
#define PCMD_CMP2_SIZE			8
#define PCMD_AND_SIZE			8
#define PCMD_NOP_SIZE			4

/* RAM */
#define PMU_RAM_SMU_USIAS0GCLKCTRL	0x2004
#define PMU_RAM_SMU_POWERSTATUS		0x2700
#define PMU_RAM_RUNCHECK			0x2710

/* commands */
#define PCMD_REG_WRITE(macro, addr, data, cmd_adr) {			\
	outl((CMD_REG_WRITE | macro | addr), cmd_adr++);			\
	outl(data, cmd_adr++);										\
}
#define PCMD_USI0_WRITE(addr, data, cmd_adr) {					\
	outl((CMD_USI0_WRITE | addr), cmd_adr++);					\
	outl(data, cmd_adr++);										\
}
#define PCMD_SP0_WRITE(addr, data, cmd_adr) {					\
	PCMD_USI0_WRITE(addr, data, cmd_adr)						\
}
#define PCMD_REG_READ(macro, addr, aorb, cmd_adr) {				\
	outl((CMD_REG_READ | aorb | macro | addr), cmd_adr++);		\
}
#define PCMD_RMW(macro, addr, data, data_en, cmd_adr) {			\
	outl((CMD_RMW | macro | addr), cmd_adr++);					\
	outl(data, cmd_adr++);										\
	outl(data_en, cmd_adr++);									\
}
#define PCMD_AND(data, aorb, cmd_adr) {							\
	outl((CMD_AND | aorb), cmd_adr++);							\
	outl(data, cmd_adr++);										\
}
#define PCMD_CMP2(data, aorb, cmd_adr) {						\
	outl((CMD_CMP2 | aorb), cmd_adr++);							\
	outl(data, cmd_adr++);										\
}
#define PCMD_REG_WRITE2(macro, addr, aorb, cmd_adr) {			\
	outl((CMD_REG_WRITE2 | aorb | macro | addr), cmd_adr++);	\
}
#define PCMD_BRANCH(jump, op, cmd_adr) {						\
	outl((CMD_BRANCH | op | jump), cmd_adr++);					\
}
#define PCMD_AJUMP(jump, cmd_adr) {								\
	outl((CMD_AJUMP | (jump)), cmd_adr++);						\
}
#define PCMD_SUBROUTINE_START(jump, cmd_adr) {					\
	outl((CMD_SUBROUTINE_START | jump), cmd_adr++);				\
}
#define PCMD_RFS(cmd_adr) {										\
	outl(CMD_RFS, cmd_adr++);									\
}
#define PCMD_INTWAIT(cmd_adr) {									\
	outl(CMD_INTWAIT, cmd_adr++);								\
}
#define PCMD_SMU_READY_WAIT(level, cmd_adr) {					\
	outl((CMD_SMU_READY_WAIT | level), cmd_adr++);				\
}
#define PCMD_TRIG_WAIT(count, trig, cmd_adr) {					\
	outl((CMD_TRIG_WAIT | trig | count), cmd_adr++);			\
}
#define PCMD_INT_MASK(mask, cmd_adr) {							\
	outl((CMD_INT_MASK | mask), cmd_adr++);						\
}
#define PCMD_WDT_STOP(cmd_adr) {								\
	outl(CMD_WDT_STOP, cmd_adr++);								\
}
#define PCMD_WDT_RESTART(cmd_adr) {								\
	outl(CMD_WDT_RESTART, cmd_adr++);							\
}
#define PCMD_PMU_END(cmd_adr) {									\
	outl(CMD_PMU_END, cmd_adr++);								\
}
#define PCMD_NOP(cmd_adr) {										\
	outl(CMD_NOP, cmd_adr++);									\
}


/**************/
/*@ variables */
/**************/

/* boot factor */
static unsigned char factor1;
static unsigned char factor2;
static unsigned char factor3;
static unsigned char wrstfct;

/* regulator counter */
static int regulator_count[REGULATOR_MAX] = {0};


/***************/
/*@ Prototypes */
/***************/

static void setup_pmu(void);
static void set_pmu_poweroff_sequence(void);
static void pw_ic_mask(void);

void cpu_idle(void);


/********************/
/*@ Global routines */ 
/********************/

/*-----------------------------------------------------------------------------
 * Function : pmu_init
 * Abstruct : Initialize PMU
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_init(void)
{
	/* get factor */
	if (pwc_read(PWC_INTC_FACTOR1, &factor1) < 0) 
		factor1 = 0; 
	if (pwc_read(PWC_INTC_FACTOR2, &factor2) < 0) 
		factor2 = 0; 
	if (pwc_read(PWC_INTC_FACTOR3, &factor3) < 0) 
		factor3 = 0; 
	if (pwc_read(PWC_INTC_WRSTFCT, &wrstfct) < 0) 
		wrstfct = 0; 

	/* clear RTCINT if AFG is not set */
#ifdef CONFIG_ICX
	if (rtc_is_alarm() == 0)
#endif
		factor3 &= ~PWC_INTC_FACTOR3_FRTCINT;

	/* clear factor */
	pwc_write(PWC_INTC_CLRFACT1, PWC_INTC_FACTOR_ALL,  PWC_INTC_FACTOR_ALL );
	pwc_write(PWC_INTC_CLRFACT2, PWC_INTC_FACTOR_ALL,  PWC_INTC_FACTOR_ALL );
	pwc_write(PWC_INTC_CLRFACT3, PWC_INTC_FACTOR_ALL,  PWC_INTC_FACTOR_ALL );
	pwc_write(PWC_INTC_WRSTCL,   PWC_INTC_WRSTFCT_ALL, PWC_INTC_WRSTFCT_ALL);

	/* regusb off */
	/* [TODO?] */

	/* change core voltage */
	pwc_write(PWC_PWR_VOUTSET1, VOUTSET1_VL0SET2_1125, VOUTSET1_VL0SET2_MASK);
	pwc_write(PWC_PWR_VOUTSET2, VOUTSET2_VPLLSET_1125, VOUTSET2_VPLLSET_MASK);
#ifdef CONFIG_ICD
	pwc_write(PWC_PWR_VOUTSET3, VOUTSET3_VGP4SET_310,  VOUTSET3_VGP4SET_MASK);
#endif

	/************************/
	/* setup charge control */
	/************************/

	/* CHG1 off */
	pwc_write(PWC_CHG_VCHG1CNT, VCHG1CNT_RVCHG1ENB, VCHG1CNT_RVCHG1ENB);

	/* none suspend, charge stop, vbus limit = 500mA */
	pwc_write(PWC_CHG_VCHG2CNT,
			  (                     0 | VCHG2CNT_RCHG2DIS	   | VCHG2CNT_RCHG2LIM_500 ),
			  (VCHG2CNT_RSUSPEND_MASK | VCHG2CNT_RCHG2ENB_MASK | VCHG2CNT_RCHG2LIM_MASK));
	
	/* enable register control */
	pwc_write(PWC_CHG_VCHG2CNT, VCHG2CNT_EN_REG, VCHG2CNT_EN_REG_MASK);

	/* set charge current to high */
	pwc_write(PWC_CHG_FET2CNT, ICHGSET_100, ICHGSET_MASK);

	/* set thrm temp to 45c (default) */
	pwc_write(PWC_CHG_BTMPSET, BTEMPHSET_45, BTEMPHSET_MASK);

	/* initialize boot flag */
	pmu_save_boot_flag(0, 0);
}

/*-----------------------------------------------------------------------------
 * Function : pmu_get_boot_media
 * Abstruct : Get boot media
 * Input    : none
 * Returen  : 0x00000004 : SD
 *			: 0x00000006 : eMMC
 *----------------------------------------------------------------------------*/
unsigned int pmu_get_boot_media(void)
{
	unsigned int mode;

	mode = inl(CHG_BOOT_MODE) & CHG_BOOT_MODE_MASK;

	return mode;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_get_power_supply_state
 * Abstruct : Get power supply
 * Input    : none
 * Returen  : 0x00000010 : AC adaptor
 *			: 0x00000020 : USB
 *----------------------------------------------------------------------------*/
unsigned int pmu_get_power_supply_state(void)
{
	unsigned char state;

	if (pwc_read(PWC_CHG_PSW_STATE, &state) < 0) 
		state = 0; 

	return (unsigned int)state;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_get_boot_factor
 * Abstruct : Save a boot factor
 * Input    : none
 * Returen  : boot factor
 *          :   bit 31-26: 
 *          :          25: wdt
 *          :          24: 
 *          :          23: usb
 *          :          22: adp
 *          :       21-18: 
 *          :          17: rtc
 *          :          16:
 *          :       15- 8: 
 *          :           7: acc
 *          :           6: key wake 
 *			:		 5- 4
 *          :           3: 
 *          :           2: 
 *          :           1: hold key
 *          :           0: 
 *----------------------------------------------------------------------------*/
unsigned int pmu_get_boot_factor(void)
{
	return (((unsigned int)wrstfct << BOOT_WRSTFCT_SHIFT)
	      | ((unsigned int)factor3 << BOOT_FACTOR3_SHIFT)
		  | ((unsigned int)factor2 << BOOT_FACTOR2_SHIFT)
		  | ((unsigned int)factor1 << BOOT_FACTOR1_SHIFT));
}

/*-----------------------------------------------------------------------------
 * Function : pmu_save_boot_factor
 * Abstruct : Save a boot factor
 * Input    : factor	: boot factor
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_save_boot_factor(unsigned int factor)
{
	unsigned int f1, f2, f3, rf;

	f1 = (factor >> BOOT_FACTOR1_SHIFT) & 0xFF;
	f2 = (factor >> BOOT_FACTOR2_SHIFT) & 0xFF;
	f3 = (factor >> BOOT_FACTOR3_SHIFT) & 0xFF;
	rf = (factor >> BOOT_WRSTFCT_SHIFT) & 0xFF;

	/* save to SRAM */
	outl((BOOT_FACTOR1_SAVE_MAGIC | f1), BOOT_FACTOR1_SAVE_ADDR);
	outl((BOOT_FACTOR2_SAVE_MAGIC | f2), BOOT_FACTOR2_SAVE_ADDR);
	outl((BOOT_FACTOR3_SAVE_MAGIC | f3), BOOT_FACTOR3_SAVE_ADDR);
	outl((BOOT_WRSTFCT_SAVE_MAGIC | rf), BOOT_WRSTFCT_SAVE_ADDR);
}

/*-----------------------------------------------------------------------------
 * Function : pmu_get_battery_value
 * Abstruct : Get battery value
 * Input    : none
 * Returen  : battery value
 *----------------------------------------------------------------------------*/
unsigned int pmu_get_battery_value(void)
{
	unsigned int val;
	int			 ret;

	ret = adc_read(VBAT_ADC_CH, &val);
	if (ret < 0)
		val = 0;

	return val;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_get_battery_threshold
 * Abstruct : Get battery threshold
 * Input    : low		: threshold of low battery
 *			: very_low	: threshold of very low battery
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_get_battery_threshold(unsigned int *low, unsigned int *very_low)
{
#if defined(CONFIG_ICX)
	if ((low == NULL) || (very_low == NULL))
		return;
	
	*low      = BTT_LOW + BTT_LOW_ALPHA;
	*very_low = BTT_VERY_LOW;
#endif /* CONFIG_ICX */

	return;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_save_boot_flag
 * Abstruct : Save a boot flag
 * Input    : target	: kind of boot flag
 *			: value		: flag value
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_save_boot_flag(unsigned int target, unsigned int value)
{
	unsigned int flag;

	flag = inl(BATTERY_FLAG_SAVE_ADDR);

	if ((flag & MAGIC_MASK) != BATTERY_FLAG_SAVE_MAGIC)
		flag = 0;

	outl((BATTERY_FLAG_SAVE_MAGIC | (flag & ~target) | value), BATTERY_FLAG_SAVE_ADDR);   

	return;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_set_vbus_limit
 * Abstruct : Set Vbus limit
 * Input    : limit	: 100/500
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_set_vbus_limit(int limit)
{
	if (limit == VBUS_LIMIT_0) {
		/* RSUSPEND	 : 1   */
		pwc_write(PWC_CHG_VCHG2CNT, VCHG2CNT_RSUSPEND, VCHG2CNT_RSUSPEND_MASK);
	}
	else if (limit == VBUS_LIMIT_100) {
		/* RSUSPEND	 : 0   */
		/* RVCHG2LIM : 100 */
		pwc_write(PWC_CHG_VCHG2CNT,
				  (                     0 | VCHG2CNT_RCHG2LIM_100 ),
				  (VCHG2CNT_RSUSPEND_MASK | VCHG2CNT_RCHG2LIM_MASK));
	}
	else { /* 500 */
		/* RSUSPEND	 : 0   */
		/* RVCHG2LIM : 500 */
		pwc_write(PWC_CHG_VCHG2CNT,
				  (                     0 | VCHG2CNT_RCHG2LIM_500 ),
				  (VCHG2CNT_RSUSPEND_MASK | VCHG2CNT_RCHG2LIM_MASK));
	}
}

/*-----------------------------------------------------------------------------
 * Function : pmu_set_reset_flg
 * Abstruct : Set the reset flag
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_set_reset_flag(void)
{
	outl(RESET_FLAG_SAVE_VALUE, RESET_FLAG_SAVE_ADDRESS);

	return;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_clear_reset_flg
 * Abstruct : Clear the reset flag
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_clear_reset_flag(void)
{
	outl(0, RESET_FLAG_SAVE_ADDRESS);

	return;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_check_reset_flg
 * Abstruct : Check the reset flag
 * Input    : none
 * Returen  : 0 : not detected
 *			: 1 : detected
 *----------------------------------------------------------------------------*/
int pmu_check_reset_flag(void)
{
	unsigned int val;
	int			 ret;

	val = inl(RESET_FLAG_SAVE_ADDRESS);

	if (val == RESET_FLAG_SAVE_VALUE)
		ret = 1;
	else
		ret = 0;

	return ret;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_regulator_on
 * Abstruct : Regulator ON
 * Input    : regulator : regulator info
 * Returen  :  0 : OK
 *			: -1 : NG
 *----------------------------------------------------------------------------*/
int pmu_regulator_on(unsigned int regulator)
{
	unsigned int address;
	unsigned int mask;
	unsigned int index;
	unsigned int data;

	address = (unsigned int)((regulator >> 0) & 0xFF);
	mask    = (unsigned int)((regulator >> 8) & 0xFF);
	index   = (unsigned int)((regulator >>16) & 0xFF);
	data    = 0xFFFF;

	if (index >= REGULATOR_MAX)
		return(-1);

	if ((address != PWC_PWR_PSCNT1)
	 && (address != PWC_PWR_PSCNT2)
	 && (address != PWC_USB_USBCONT))
		return(-1);
	
	if ((regulator == REGULATOR_R1) || (regulator == REGULATOR_R2)) {
		pwc_write(PWC_PWR_PSCNT1, 0x10, 0x10);		/* turn on PWC_PSCNTDD2 */
		udelay(50000);
	}

	pwc_write(address, data, mask);

	regulator_count[index]++;

	return 0;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_regulator_off
 * Abstruct : Regulator OFF
 * Input    : regulator : regulator info
 * Returen  :  0 : OK
 *			: -1 : NG
 *----------------------------------------------------------------------------*/
int pmu_regulator_off(unsigned int regulator)
{
	unsigned int address;
	unsigned int mask;
	unsigned int index;
	unsigned int data;

	address = (unsigned int)((regulator >> 0) & 0xFF);
	mask    = (unsigned int)((regulator >> 8) & 0xFF);
	index   = (unsigned int)((regulator >>16) & 0xFF);
	data    = 0x0000;

	if (index >= REGULATOR_MAX)
		return(-1);

	if ((address != PWC_PWR_PSCNT1)
	 && (address != PWC_PWR_PSCNT2)
	 && (address != PWC_USB_USBCONT))
		return(-1);

	if (regulator_count[index] <= 1) {

		pwc_write(address, data, mask);

		if ((regulator == REGULATOR_R1) || (regulator == REGULATOR_R2)) {
			udelay(50000);
			pwc_write(PWC_PWR_PSCNT1, 0x00, 0x10);		/* turn off PWC_PSCNTDD2 */
		}
	}

	if (regulator_count[index] > 0)
		regulator_count[index]--;

	return 0;
}

/*-----------------------------------------------------------------------------
 * Function : pmu_power_off
 * Abstruct : Power off sequence
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
void pmu_power_off(void)
{
	unsigned char reg;

	/**********************/
	/* mask all interrupt */
	/**********************/

	/* disbale fiq */
	/* u-boot does not enable fiq. */

	/* disable irq */
	/* u-boot does not enable irq. */

	/* disable int */
	outl(GIC_INT_MASK_ALL, GIC_DIST_ENABLE_CLEAR + 0x00);
	outl(GIC_INT_MASK_ALL, GIC_DIST_ENABLE_CLEAR + 0x04);
	outl(GIC_INT_MASK_ALL, GIC_DIST_ENABLE_CLEAR + 0x08);
	outl(GIC_INT_MASK_ALL, GIC_DIST_ENABLE_CLEAR + 0x0C);
	outl(GIC_INT_MASK_ALL, GIC_DIST_ENABLE_CLEAR + 0x10);

	/* disable gpio int */
	outl(GIO_IDS_MASK_ALL, GIO_000_IDS);
	outl(GIO_IDS_MASK_ALL, GIO_032_IDS);
	outl(GIO_IDS_MASK_ALL, GIO_064_IDS);
	outl(GIO_IDS_MASK_ALL, GIO_096_IDS);
	outl(GIO_IDS_MASK_ALL, GIO_128_IDS);

	/*************/
	/* setpu pmu */
	/*************/

	setup_pmu();

	/* Auto Frq Change Disable */
    outl(inl(SMU_CKRQ_MODE) & ~0x00000001, SMU_CKRQ_MODE);

	/********************/
	/* enable interrupt */
	/********************/

	/* setup RTC poweron register */
	pwc_read(PWC_RTC_RTC1_RD, &reg);
	if (reg & PWC_RTC_RTC1_ALE)
		pwc_write(PWC_INTC_WRSTMSK, 0x01, 0xFF);
	else
		pwc_write(PWC_INTC_WRSTMSK, 0x00, 0xFF);

	/* ACC_DET      through 0x80 */
	/* KEY_WAKE     through 0x40 */
	/* PWC_GPIO_05  mask    0x00 */
	/* PWC_GPIO_04  mask    0x00 */
	/* PWC_GPIO_03  mask    0x00 */
	/* KEY_XNC      mask    0x00 */
	/* KEY_XHOLD    through 0x02 */
	/* PWC_GPIO_00  mask    0x00 */
	pwc_write(PWC_INTC_REGPWONMSK, 0xC2, 0xFF);

	/****************/
	/* mode control */
	/****************/

	/* VGP4PS   : Power Save */
	/* VGP3PS   : Power Save */
	/* VGP1PS   : Power Save */
	/* DDIOPS   : ECOREG     */
	/* PSCNTL0  : REGPLL=OFF */
	/* PSCNTDDL1: OFF        */
	pwc_write(PWC_PWR_REGA, 0x74, 0xFF);

	/*******/
	/* WFI */
	/*******/

	/* goto idle(wfi) and wait power off */
	cpu_idle();
}


/*******************/
/*@ Local routines */ 
/*******************/

/*-----------------------------------------------------------------------------
 * Function : setup_pmu
 * Abstruct : setup PMU when power off
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
static void setup_pmu(void)
{
	unsigned int regval;

	/* set PMU command sequence */
	set_pmu_poweroff_sequence();

	/* if P0_ON ? */
	outl(0x00111011, SMU_P0_SWENA);		/* RAM Disable */

	/* Set IRQ of PowerIC */
	pw_ic_mask();

	/* INT set(sec) */
	outl(0x00000001, PMU_INTFFCLR_M);
	outl(0x00000003, PMU_INTFFCLR_A);
	outl(0x00000001, PMU_INTENSET_M);
	outl(0x00000003, PMU_INTENSET_A);

	outl(0x00040B04, SMU_P1_RFF_PARA1);

	outl(PMU_PC_MAIN, PMU_PC);			/* 1000 */
	outl(PMU_PC_ON2, PMU_POWER_ON_PC);	/* 12C0 */
	outl(PMU_PC_ON2, PMU_INT_HANDLER_PC);

	outl(PMU_WDT_ENABLE, PMU_WDT_COUNT_EN);
	outl(PMU_WDT_MAX_COUNT, PMU_WDT_COUNT_LMT);

	/* pmu start */
	outl(PMU_START_SET, PMU_START);
	do {
		regval = inl(PMU_START);
	} while ((regval & PMU_START_SET) != PMU_START_SET);
}

/*-----------------------------------------------------------------------------
 * Function : set_pmu_poweroff_sequence
 * Abstruct : set poweroff sequence to PMU registers
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
static void set_pmu_poweroff_sequence(void)
{
	unsigned int *pmu_cmd_adr;
	unsigned int  tmp_pc;
	unsigned int  value;

	/* 1000 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_MAIN);

	PCMD_INT_MASK(PMU_INT_MASK, pmu_cmd_adr);

	/* 0x1008: here is return position */
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_POWER_STATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_REG_WRITE2(PMU_MACRO, PMU_RAM_SMU_POWERSTATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_SUBROUTINE_START(PMU_PC_SUB_SWOFF0, pmu_cmd_adr);	/* PowerSW OFF #0 */

	/* economy mode */
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_CLK_MODE_SEL, 0x0005, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_SMU_READY_WAIT(PMU_HIGH_LEVEL, pmu_cmd_adr);
	
	PCMD_AJUMP(PMU_PC_PWRCNT2, pmu_cmd_adr);

	/* 1200 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_ON1);
	tmp_pc = PMU_VIRADDR_TO_PC(pmu_cmd_adr);

	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000FFF, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to 0x1200 */
	PCMD_SUBROUTINE_START(PMU_PC_SUB_SETPARA, pmu_cmd_adr);	/* to 0x1A00 */

	PCMD_NOP(pmu_cmd_adr);
	PCMD_SUBROUTINE_START(PMU_PC_SUB_SWON2, pmu_cmd_adr);	/* to 0x1750 */
	PCMD_SUBROUTINE_START(PMU_PC_SUB_SWON0, pmu_cmd_adr);	/* to 0x1500 */

	PCMD_REG_WRITE(PMU_MACRO, PMU_RAM_RUNCHECK, 0x00000001, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_MEMC_HAND_SHAKE_FAKE, 0x00000000, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_CLK_MODE_SEL, 0x00000001, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_SMU_READY_WAIT(PMU_HIGH_LEVEL, pmu_cmd_adr);
	PCMD_WDT_STOP(pmu_cmd_adr);
	PCMD_TRIG_WAIT(1, PMU_TRIG_INT | PMU_TRIG_P1WAKEUP_LOW, pmu_cmd_adr);
	PCMD_WDT_RESTART(pmu_cmd_adr);
	PCMD_AND(0x00000038, PMU_REGA, pmu_cmd_adr);
	PCMD_CMP2(0x00000008, PMU_REGA, pmu_cmd_adr);
	PCMD_BRANCH(0x1004, PMU_BEQ, pmu_cmd_adr);				/* 0x1004@PMU_PC_MAIN */
	
	if (!(inl(SMU_CPUCLK_SYNCSET) & 0x01)) {
		tmp_pc = PMU_VIRADDR_TO_PC(pmu_cmd_adr);
		PCMD_REG_READ(SMU_MACRO, SMU_CMD_PLL_STATUS, PMU_REGB, pmu_cmd_adr);
		PCMD_AND(0x00000010, PMU_REGB, pmu_cmd_adr);
		PCMD_CMP2(0x00000010, PMU_REGB, pmu_cmd_adr);
		PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	}
	PCMD_AJUMP(PMU_PC_ON2, pmu_cmd_adr);					/* to 0x12C0 */

	/* PMU_PC_ON2 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_ON2);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PMU_INTCTRL, 0x00000001, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PMU_INTCTRL, 0x00000000, pmu_cmd_adr);
	PCMD_PMU_END(pmu_cmd_adr);

	/* PMU_PC_PWRCNT2 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_PWRCNT2);
	PCMD_SUBROUTINE_START(PMU_PC_SUB_VDD_SPI, pmu_cmd_adr);
	PCMD_SUBROUTINE_START(PMU_PC_SUB_SPI1, pmu_cmd_adr);		/* to 0x1940 */
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_TX_DATA, 0x00004CC2, pmu_cmd_adr);
	PCMD_SP0_WRITE(SIO_CMD_SP0_CONTROL, 0x00000009, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_FFCLR, 0x000000FF, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_TX_DATA, 0x00000274, pmu_cmd_adr);
	PCMD_SP0_WRITE(SIO_CMD_SP0_CONTROL, 0x00000009, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_FFCLR, 0x000000FF, pmu_cmd_adr);
	PCMD_SUBROUTINE_START(PMU_PC_SUB_SPI2, pmu_cmd_adr);     /* to 0x1980 */

	PCMD_INTWAIT(pmu_cmd_adr);

	/* PMU_PC_SUB_SWOFF0 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SWOFF0);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_RMW(SMU_MACRO, SMU_CMD_PV_SWON, 0x00000000, 0x00000001, pmu_cmd_adr);
	PCMD_RMW(SMU_MACRO, SMU_CMD_PR_SWON, 0x00000000, 0x00000001, pmu_cmd_adr);
	PCMD_RMW(SMU_MACRO, SMU_CMD_PG_SWON, 0x00000000, 0x00000001, pmu_cmd_adr);
	PCMD_RMW(SMU_MACRO, SMU_CMD_PU_SWON, 0x00000000, 0x00000001, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000760, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to 0x1348 */
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SWOFF2 */
	/* 1400 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SWOFF2);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_DDR_STATE8, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000003, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000003, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(PMU_PC_SUB_SWOFF2, PMU_BNE, pmu_cmd_adr);	/* to up */

	PCMD_REG_READ(SMU_MACRO, SMU_CMD_P1_SWON, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000100, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000100, PMU_REGB, pmu_cmd_adr);
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr)
		+ PCMD_BRANCH_SIZE
		+ PCMD_NOP_SIZE;
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_NOP(pmu_cmd_adr);
	PCMD_RMW(SMU_MACRO, SMU_CMD_CPUGCLKCTRL, 0x00000000, 0x00000004, pmu_cmd_adr);
	PCMD_RMW(SMU_MACRO, SMU_CMD_P1_SWON, 0x00000000, 0x00000001, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_MEMC_HAND_SHAKE_FAKE, 0x00000001, pmu_cmd_adr);
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000010, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SWOFF3 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SWOFF3);
	PCMD_RMW(SMU_MACRO, SMU_CMD_P0_SWON, 0x00000000, 0x00000001, pmu_cmd_adr);
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SWON0 */
	/* 1500 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SWON0);
	PCMD_REG_READ(PMU_MACRO, PMU_RAM_SMU_POWERSTATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00003000, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr)
		+ PCMD_BRANCH_SIZE
		+ PCMD_RMW_SIZE
		+ PCMD_REG_READ_SIZE
		+ PCMD_AND_SIZE
		+ PCMD_CMP2_SIZE
		+ PCMD_BRANCH_SIZE;
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* jump over */
	PCMD_RMW(SMU_MACRO, SMU_CMD_PU_SWON, 0x00000001, 0x00000001, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000040, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_REG_READ(PMU_MACRO, PMU_RAM_SMU_POWERSTATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000C000, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr)
		+ PCMD_BRANCH_SIZE
		+ PCMD_RMW_SIZE
		+ PCMD_REG_READ_SIZE
		+ PCMD_AND_SIZE
		+ PCMD_CMP2_SIZE
		+ PCMD_BRANCH_SIZE;
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* jump over */

	PCMD_RMW(SMU_MACRO, SMU_CMD_PG_SWON, 0x00000001, 0x00000001, pmu_cmd_adr);
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000100, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_REG_READ(PMU_MACRO, PMU_RAM_SMU_POWERSTATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00300000, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr)
		+ PCMD_BRANCH_SIZE
		+ PCMD_RMW_SIZE
		+ PCMD_REG_READ_SIZE
		+ PCMD_AND_SIZE
		+ PCMD_CMP2_SIZE
		+ PCMD_BRANCH_SIZE;
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* jump over */
	PCMD_RMW(SMU_MACRO, SMU_CMD_PR_SWON, 0x00000001, 0x00000001, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000400, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_REG_READ(PMU_MACRO, PMU_RAM_SMU_POWERSTATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x000C0000, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr)
		+ PCMD_BRANCH_SIZE
		+ PCMD_RMW_SIZE
		+ PCMD_REG_READ_SIZE
		+ PCMD_AND_SIZE
		+ PCMD_CMP2_SIZE
		+ PCMD_BRANCH_SIZE;
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_RMW(SMU_MACRO, SMU_CMD_PV_SWON, 0x00000001, 0x00000001, pmu_cmd_adr);

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000200, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to 0x1614 */

	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_PLL_STATUS, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000010, PMU_REGB, pmu_cmd_adr);	/* PLL2 */
	PCMD_CMP2(0x00000010, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SWON2 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SWON2);
	PCMD_RMW(SMU_MACRO, SMU_CMD_P1_SWON, 0x00000001, 0x00000001, pmu_cmd_adr);
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000010, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to 0x175C */
	PCMD_RMW(SMU_MACRO, SMU_CMD_CPUGCLKCTRL, 0x00000004, 0x00000004, pmu_cmd_adr);
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SWON3 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SWON3);
	PCMD_RMW(SMU_MACRO, SMU_CMD_P0_SWON, 0x00000001, 0x00000001, pmu_cmd_adr);
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_SEQ_BUSY, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000001, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);				/* to up */
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SPI1 */
	/* 1940 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SPI1);
	PCMD_REG_READ(SMU_MACRO, SMU_CMD_USIAS0GCLKCTRL, PMU_REGB, pmu_cmd_adr);
	PCMD_REG_WRITE2(PMU_MACRO, PMU_RAM_SMU_USIAS0GCLKCTRL, PMU_REGB, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_USIAS0GCLKCTRL, 0x00000007, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_FFCLR, 0x000000FF, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_ENSET, 0x000000FF, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_POL, 0x00007004, pmu_cmd_adr);
	PCMD_REG_WRITE(SIO0_MACRO, SIO_CMD_SP0_MODE, 0x00000F04, pmu_cmd_adr);
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SPI2 */
	/* 1980 */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SPI2);
	PCMD_REG_READ(PMU_MACRO, PMU_RAM_SMU_USIAS0GCLKCTRL, PMU_REGB, pmu_cmd_adr);
	PCMD_REG_WRITE2(SMU_MACRO, SMU_CMD_USIAS0GCLKCTRL, PMU_REGB, pmu_cmd_adr);
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_SETPARA */
	pmu_cmd_adr = PMU_PC_TO_VIRADDR(PMU_PC_SUB_SETPARA);
	value = 0x00000085;
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_P0_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_P1_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PD_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PU_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PG_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PR_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_REG_WRITE(SMU_MACRO, SMU_CMD_PV_PWSW_PARA, value, pmu_cmd_adr);
	PCMD_RFS(pmu_cmd_adr);

	/* PMU_PC_SUB_VDD_SPI */
	pmu_cmd_adr = (unsigned int*)PMU_PC_TO_VIRADDR(PMU_PC_SUB_VDD_SPI);

	/**************************************/
	/********* MEMC_DEEP_POWERDOWN ********/
	/**************************************/

	/* MEMC DPD-0 auto power down:disable */
	PCMD_RMW(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGR3, 0x00000000, 0x00000101, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);

	/* MEMC_DPD-1 Auto-SREF, Auto-CBR:disable */
	PCMD_RMW(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGR2, 0x00000000, 0x00000303, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);

	/* CMD CLEAR */
	/* ready */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x000000c0, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	/* MEMC_DPD-2 all bank precharge */
	PCMD_RMW(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC1, 0x00000400, 0x00000400, pmu_cmd_adr);
	/* ready */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x00000099, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000009, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	/* CMD CLEAR */
	/* ready */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x000000c0, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	/* MEMC_DPD-3 CKE */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	/* ready */
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x0000009d, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x0000000d, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	/* CMD CLEAR */
	/* ready */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x000000c0, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	/* MEMC_DPD-5 Deep Power Down */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	/* ready */
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x0000009c, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x0000000c, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* check state */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_STATE8, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000007, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	/* CMD CLEAR */
	/* ready */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000300, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);
	/* write */
	PCMD_REG_WRITE(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, 0x000000c0, pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	PCMD_NOP(pmu_cmd_adr);
	/* read */
	tmp_pc = PMU_VIRADDR_TO_PC((unsigned int)pmu_cmd_adr);
	PCMD_REG_READ(MEMC_MACRO, MEMC_CMD_MEMC_DDR_CONFIGC2, PMU_REGB, pmu_cmd_adr);
	PCMD_AND(0x0000000f, PMU_REGB, pmu_cmd_adr);
	PCMD_CMP2(0x00000000, PMU_REGB, pmu_cmd_adr);
	PCMD_BRANCH(tmp_pc, PMU_BNE, pmu_cmd_adr);

	PCMD_RFS(pmu_cmd_adr);

	return;
}

/*-----------------------------------------------------------------------------
 * Function : pw_ic_mask
 * Abstruct : set IRQ of PowerIC
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
static void pw_ic_mask(void)
{
	unsigned char reg;

	/****************/
	/* pull control */
	/****************/

	/* (WF_HOST_WAKE) pull-down 0x04 */
	/* WF_RF285_ON    pull-down 0x01 */
	pwc_write(PWC_GPIO_GPPUPD4, 0x05, 0xFF);

	/* HP_XMUTE3      pull-down 0x40 */
	/* PWC_GPIO_10    pull-down 0x10 */
	/* USB_WAKE       pull-down 0x04 */
	/* BT_HOST_WAKE   pull-down 0x01 */
	pwc_write(PWC_GPIO_GPPUPD3, 0x55, 0xFF);

	/* ACC_DET        pull-down 0x40 */
	/* KEY_WAKE       pull-none 0x00 */
	/* PWC_GPIO_05    pull-down 0x04 */
	/* PWC_GPIO_04    pull-down 0x01 */
	pwc_write(PWC_GPIO_GPPUPD2, 0x45, 0xFF);

	/* PWC_GPIO_03    pull-down 0x40 */
	/* KEY_XNC        pull-none 0x00 */
	/* KEY_XHOLD      pull-none 0x00 */
	/* PWC_GPIO_00    pull-down 0x01 */
	pwc_write(PWC_GPIO_GPPUPD1, 0x41, 0xFF);

	/****************/
	/* output value */
	/****************/

	/* (WF_HOST_WAKE) low  0x00 */
	/* WF_RF285_ON    low  0x00 */
	/* HP_XMUTE3      low  0x00 */
	/* PWC_GPIO_10    low  0x00 */
	/* USB_WAKE       low  0x00 */
	/* BT_HOST_WAKE   low  0x00 */
	pwc_write(PWC_GPIO_IOOUT2, 0x00, 0xFF);

	/* ACC_DET        low  0x00 */
	/* KEY_WAKE       low  0x00 */
	/* PWC_GPIO_05    low  0x00 */
	/* PWC_GPIO_04    low  0x00 */
	/* PWC_GPIO_03    low  0x00 */
	/* KEY_XNC        low  0x00 */
	/* KEY_XHOLD      low  0x00 */
	/* PWC_GPIO_00    low  0x00 */
	pwc_write(PWC_GPIO_IOOUT1, 0x00, 0xFF);

	/******************/
	/* port direction */
	/******************/

	/* (WF_HOST_WAKE) in  0x00 */
	/* WF_RF285_ON    in  0x00 */
	/* HP_XMUTE3      in  0x00 */
	/* PWC_GPIO_10    in  0x00 */
	/* USB_WAKE       in  0x00 */
	/* BT_HOST_WAKE   in  0x00 */
	pwc_write(PWC_GPIO_IOSEL2, 0x00, 0xFF);

	/* ACC_DET        in  0x00 */
	/* KEY_WAKE       in  0x00 */
	/* PWC_GPIO_05    in  0x00 */
	/* PWC_GPIO_04    in  0x00 */
	/* PWC_GPIO_03    in  0x00 */
	/* KEY_XNC        in  0x00 */
	/* KEY_XHOLD      in  0x00 */
	/* PWC_GPIO_00    in  0x00 */
	pwc_write(PWC_GPIO_IOSEL1, 0x00, 0xFF);

	/*************************/
	/* interrupt detect mode */
	/*************************/

	/* RTC_INT        rise 0x04 */
	pwc_write(PWC_INTC_DETMOD3L, 0x04, 0x0C);

	/* DETUSB_INT     rise 0x40 */
	pwc_write(PWC_INTC_DETMOD3H, 0x40, 0xC0);

	/* ACC_DET        rise 0x40 */
	/* KEY_WAKE       rise 0x10 */
	pwc_write(PWC_INTC_DETMOD1H, 0x50, 0xF0);

	/* KEY_XHOLD      both 0x04 */
	pwc_write(PWC_INTC_DETMOD1L, 0x04, 0x0C);

	/****************/
	/* clear factor */
	/****************/

	/* RTC int reset */
	pwc_read(PWC_RTC_RTC1_RD, &reg);
	if (reg & PWC_RTC_RTC1_ALE) {
		pwc_write(PWC_RTC_RTC1, (reg & ~PWC_RTC_RTC1_ALE), 0xFF);
		pwc_write(PWC_RTC_RTC1, reg, 0xFF);
	}

	udelay(1000);

	/* clear RTC factor */
	pwc_write(PWC_INTC_WRSTCL, 0xFF, 0xFF);

	/******************************/
	/* device side interrupt mask */
	/******************************/

	/* ACC_DET      through 0x80 */
	/* KEY_WAKE     through 0x40 */
	/* PWC_GPIO_05  mask    0x00 */
	/* PWC_GPIO_04  mask    0x00 */
	/* PWC_GPIO_03  mask    0x00 */
	/* KEY_XNC      mask    0x00 */
	/* KEY_XHOLD    through 0x02 */
	/* PWC_GPIO_00  mask    0x00 */
	pwc_write(PWC_INTC_FMASK1,   0xC2, 0xFF);
	udelay(50000);	/* delay for chattering cancellation */
	pwc_write(PWC_INTC_CLRFACT1, 0xC2, 0xFF);
	pwc_write(PWC_INTC_BMASK1,   0xC2, 0xFF);

	/* ALL          mask    0x00 */
	pwc_write(PWC_INTC_FMASK2,   0x00, 0xFF);
	udelay(50000);	/* delay for chattering cancellation */
	pwc_write(PWC_INTC_CLRFACT2, 0xFF, 0xFF);
	pwc_write(PWC_INTC_BMASK2,   0x00, 0xFF);

	/* USB_DET_INT  through 0x80 */
	/* ADP_DET_INT  through 0x40 */
	/* BAT_DET_INT  mask    0x00 */
	/* CHARGE_INT   mask    0x00 */
	/* RTC_INT      through 0x02 */
	/* AD_INT       mask    0x00 */
	pwc_write(PWC_INTC_FMASK3  , 0x82, 0xFF);
	udelay(50000);	/* delay for chattering cancellation */
	pwc_write(PWC_INTC_CLRFACT3, 0x82, 0xFF);
	pwc_write(PWC_INTC_BMASK3,   0x82, 0xFF);
}

#endif /* CONFIG_ICX || CONFIG_ICD */
