/*
 *  File Name	    : linux/arch/arm/mach-mp200/pm.c
 *  Function	    : pm
 *  Release Version : Ver 1.00
 *  Release Date    : 2006/04/05
 *
 *  Copyright (C) NEC Electronics Corporation 2005-2006
 *
 *
 *  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 Free Softwere Foundation; either version 2
 *  of 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 warrnty 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.
 *
 */

/*
 * Copyright 2006,2007 Sony Corporation. 
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/rtc.h>
#include <linux/pm.h>

#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>

#include <asm/arch/gpiocore.h>
#include <asm/arch/uwire.h>
#include <asm/arch/smu.h>
#include <asm/arch/mp201_mem.h>
#include <asm/arch/pm.h>
#include <asm/arch/pmu.h>

#define PM_POWERIC_ES_SWITCH /* ES1.1 support */

#define PM_DEBUG_REG

#include "uwire.h"
#include "time.h"
#include "pmu.h"
#include "pm.h"


/* 2006.07.07 ish */
#ifdef CONFIG_MP200_PM_EXT
#include <asm/arch/mp200_pm_ext.h>
#endif

#ifdef CONFIG_SONY_ICX1087
#include <asm/arch/icx1087_power.h>
#include <asm/arch/icx1087_key.h>

static int _n_usb_suspend = 0;
#endif

#ifdef PM_POWERIC_ES_SWITCH
#define PWC_LSIVER_ES1_1 0x01
static unsigned int lsiver_old = 0;
#endif /* PM_POWERIC_ES_SWITCH */

static const unsigned int pmu_cmds_s1_suspend[] = {
/* SDR Pull Down */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PDOWN),
/* SDR Floating */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_FLOATING),
/* L1 clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* L1 auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_AHBCLKCTRL0_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_AHBCLKCTRL1_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_APBCLKCTRL_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_L1_NO_AUTO),
/* L1 Reset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, SMU_RSTENA1A_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B_ENA, SMU_RSTENA1B_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP_ENA, SMU_RSTENADSP_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP, SMU_RST_RESET),
/* SET MWI_SCLK_DIV for OSC */
	PMU_CMD_REG_WRITE(SMU_MWI_SCLK_DIV, SMU_MWI_DIV_OSC_VAL),
/* L1 power off*/
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_OFF << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_OFF),
/* wait L1 power off */
	PMU_CMD_L1_STAT_WAIT(PMU_CMDP_WAIT_FOR_POWER_OFF),
/* Clock RTC */
	PMU_CMD_REG_WRITE(SMU_PLLSEL, SMU_PLLSEL_RTC ),
/* OSC disable */
	PMU_CMD_REG_WRITE(SMU_OSC_CTRL, SMU_OSC_ENA_DISABLE),
/* INTC enable */
	PMU_CMD_REG_WRITE(VA_INTC + MP200_INTC_IT0_IEN1, PMU_RESUME_INT),
/* INTWAIT */
	PMU_CMD_INTWAIT(),
};

static const unsigned int pmu_cmds_s2_suspend[] = {
/* SDR Pull Down */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PDOWN),
/* SDR Floating */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_FLOATING),
/* L1 clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* L1 auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_AHBCLKCTRL0_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_AHBCLKCTRL1_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_APBCLKCTRL_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_L1_NO_AUTO),
/* L1 Reset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, SMU_RSTENA1A_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B_ENA, SMU_RSTENA1B_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP_ENA, SMU_RSTENADSP_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP, SMU_RST_RESET),
/* SET MWI_SCLK_DIV for OSC */
	PMU_CMD_REG_WRITE(SMU_MWI_SCLK_DIV, SMU_MWI_DIV_OSC_VAL),
/* L1 power off*/
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_OFF << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_OFF),
/* wait L1 power off */
	PMU_CMD_L1_STAT_WAIT(PMU_CMDP_WAIT_FOR_POWER_OFF),
/* Clock RTC */
	PMU_CMD_REG_WRITE(SMU_PLLSEL, SMU_PLLSEL_RTC ),
/* OSC disable */
	PMU_CMD_REG_WRITE(SMU_OSC_CTRL, SMU_OSC_ENA_DISABLE),
/* INTC enable */
	PMU_CMD_REG_WRITE(VA_INTC + MP200_INTC_IT0_IEN1, PMU_RESUME_INT),
/* INTWAIT */
	PMU_CMD_INTWAIT(),
};

static const unsigned int pmu_cmds_s3_suspend[] = {
/* SDR Pull Down */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PDOWN),
/* SDR Floating */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_FLOATING),
/* L1 clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* L1 auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_AHBCLKCTRL0_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_AHBCLKCTRL1_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_APBCLKCTRL_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_L1_NO_AUTO),
/* L1 Reset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, SMU_RSTENA1A_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B_ENA, SMU_RSTENA1B_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP_ENA, SMU_RSTENADSP_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP, SMU_RST_RESET),
/* SET MWI_SCLK_DIV for OSC */
	PMU_CMD_REG_WRITE(SMU_MWI_SCLK_DIV, SMU_MWI_DIV_OSC_VAL ),
/* INTC enable */
	PMU_CMD_REG_WRITE(VA_INTC + MP200_INTC_IT0_IEN1, PMU_RESUME_INT),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
/* WRSTCL ARST/REGRST clear */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_WRSTCL << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_WRSTCL_CLEAR << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
/* WRSTMSK INTWAK enable */
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_WRSTMSK << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_WRSTMSK_INTWAK_ENABLE << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
/* L0 power save mode 1.2V -> 0.7V */
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_VOUTSET1 << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_VOUTSET1_LP07_VAL << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
/* L1 off and L0 power save */
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
#ifdef PM_DEEPSLEEP_ECO
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_OFF_ECO_PS << 24)),
#else 
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_OFF_PS << 24)),
#endif
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
/* Clock -> RTC */
	PMU_CMD_REG_WRITE(SMU_PLLSEL, SMU_PLLSEL_RTC ),
/* OSC disable */
	PMU_CMD_REG_WRITE(SMU_OSC_CTRL, SMU_OSC_ENA_DISABLE ),
/* INTWAIT */
	PMU_CMD_INTWAIT(),
};

#ifdef PM_POWERIC_ES_SWITCH
static const unsigned int pmu_cmds_s3_suspend_es1_1[] = {
/* SDR Pull Down */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PDOWN),
/* SDR Floating */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_FLOATING),
/* L1 clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2_L1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* L1 auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_AHBCLKCTRL0_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_AHBCLKCTRL1_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_APBCLKCTRL_L1_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_L1_NO_AUTO),
/* L1 Reset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, SMU_RSTENA1A_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B_ENA, SMU_RSTENA1B_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1B, SMU_RST_RESET),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP_ENA, SMU_RSTENADSP_ALL),
	PMU_CMD_REG_WRITE(SMU_RESETREQDSP, SMU_RST_RESET),
/* SET MWI_SCLK_DIV for OSC */
	PMU_CMD_REG_WRITE(SMU_MWI_SCLK_DIV, SMU_MWI_DIV_OSC_VAL ),
/* INTC enable */
	PMU_CMD_REG_WRITE(VA_INTC + MP200_INTC_IT0_IEN1, PMU_RESUME_INT),
/* KEY REGRSTMSK enable */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGRSTMSK1 << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGRSTMSK1_ENABLE << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
/* L0 power save mode and 1.2V -> 0.7V */
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_VOUTSET1 << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_VOUTSET1_LP07_VAL << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
#ifdef PM_DEEPSLEEP_ECO
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_OFF_ECO_PS << 24)),
#else 
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_OFF_PS << 24)),
#endif
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
/* Clock -> RTC */
	PMU_CMD_REG_WRITE(SMU_PLLSEL, SMU_PLLSEL_RTC ),
/* OSC disable */
	PMU_CMD_REG_WRITE(SMU_OSC_CTRL, SMU_OSC_ENA_DISABLE ),
/* INTWAIT */
	PMU_CMD_INTWAIT(),
};
#endif /* PM_POWERIC_ES_SWITCH */

static const unsigned int pmu_cmds_s1_resume[] = {
/* auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_NO_AUTO),
/* clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* L1 power ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_ON << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_OFF),
/* SDR 32bit */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_32BIT),
/* SDR Pull Up */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PUP),
/* wait L1_RESET */
	PMU_CMD_L1_STAT_WAIT(PMU_CMDP_WAIT_FOR_POWER_ON),
/* L1(A) unreset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, MASK_SMU_1A_RSM_RST),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_UNRESET),
/* PMU_END */
	PMU_CMD_PMU_END(),
};

static const unsigned int pmu_cmds_s2_resume[] = {
/* auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_NO_AUTO),
/* clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* L1 power ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L1_ON << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_OFF),
/* SDR 32bit */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_32BIT),
/* SDR Pull Up */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PUP),
/* wait L1_RESET */
	PMU_CMD_L1_STAT_WAIT(PMU_CMDP_WAIT_FOR_POWER_ON),
/* L1(A) unreset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, MASK_SMU_1A_RSM_RST),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_UNRESET),
/* PMU_END */
	PMU_CMD_PMU_END(),
};

static const unsigned int pmu_cmds_s3_resume[] = {
/* auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_NO_AUTO),
/* clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* WRSTMSK INTWAK disable */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_WRSTMSK << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_WRSTMSK_INTWAK_DISABLE << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_OFF),
/* SDR 32bit */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_32BIT),
/* SDR Pull Up */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PUP),
/* wait L1_RESET */
	PMU_CMD_L1_STAT_WAIT(PMU_CMDP_WAIT_FOR_POWER_ON),
/* L1(A) unreset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, MASK_SMU_1A_RSM_RST),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_UNRESET),
/* PMU_END */
	PMU_CMD_PMU_END(),
};

#ifdef PM_POWERIC_ES_SWITCH
static const unsigned int pmu_cmds_s3_resume_es1_1[] = {
/* auto clock control OFF */
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL0, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_AHBCLKCTRL1, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_APBCLKCTRL, SMU_CLKCTRL_NO_AUTO),
	PMU_CMD_REG_WRITE(SMU_CLKCTRL, SMU_CLKCTRL_NO_AUTO),
/* clock gate ON */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0_ENA, MASK_SMU_GCK0),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL0, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_GCK1),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2_ENA, MASK_SMU_GCK2),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL2, SMU_GCK_ON),
/* KEY REGRSTMSK disable */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGRSTMSK1 << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGRSTMSK1_DISABLE << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_OFF),
/* SDR 32bit */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_32BIT),
/* SDR Pull Up */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PUP),
/* wait L1_RESET */
	PMU_CMD_L1_STAT_WAIT(PMU_CMDP_WAIT_FOR_POWER_ON),
/* L1(A) unreset */
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A_ENA, MASK_SMU_1A_RSM_RST),
	PMU_CMD_REG_WRITE(SMU_RESETREQ1A, SMU_RST_UNRESET),
/* PMU_END */
	PMU_CMD_PMU_END(),
};
#endif /* PM_POWERIC_ES_SWITCH */

static const unsigned int pmu_cmds_power_off[] = {
/* SDR Pull Down */
	PMU_CMD_REG_WRITE(SMU_PULLCTL_SDR, SMU_PULLCTL_SDR_PDOWN),
/* SDR Floating */
	PMU_CMD_REG_WRITE(SMU_PCTL_SDR, SMU_PCTL_SDR_FLOATING),
/* SET MWI_SCLK_DIV for OSC */
	PMU_CMD_REG_WRITE(SMU_MWI_SCLK_DIV, SMU_MWI_DIV_OSC_VAL ),
/* L0 power OFF */
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1_ENA, MASK_SMU_MWI_GCK),
	PMU_CMD_REG_WRITE(SMU_GCLKCTRL1, SMU_GCK_ON),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX),
	PMU_CMD_REG_WRITE(MWI_TXQA, (GPIOCORE_PWC_REGA << 24)),
	PMU_CMD_REG_WRITE(MWI_TXQ, (PWC_REGA_L0_OFF_ECO_PS << 24)),
	PMU_CMD_REG_WRITE(MWI_INTENSET, MWI_ENSET),
	PMU_CMD_MWI_WRITE(MWI_START, MWI_START_FLAG),
	PMU_CMD_REG_WRITE(MWI_INTFFCLR, MWI_FFCLR),
	PMU_CMD_REG_WRITE(MWI_CONT, MWI_CONT_PWC_A8_D8_TX_OFF),
/* Clock -> RTC */
	PMU_CMD_REG_WRITE(SMU_PLLSEL, SMU_PLLSEL_RTC ),
/* disable OSC */
	PMU_CMD_REG_WRITE(SMU_OSC_CTRL, SMU_OSC_ENA_DISABLE ),
/*  PMU_END */
	PMU_CMD_PMU_END(),
};

static const struct intc_t intc[] = {
	{
	 .ien = VA_INTC + MP200_INTC_IT0_IEN0,
	 .ids = VA_INTC + MP200_INTC_IT0_IDS0,
	 .imn = VA_INTC + MP200_INTC_IT0_IMN0,
	 },
	{
	 .ien = VA_INTC + MP200_INTC_IT0_IEN1,
	 .ids = VA_INTC + MP200_INTC_IT0_IDS1,
	 .imn = VA_INTC + MP200_INTC_IT0_IMN1,
	 },
};

static struct {
	unsigned int ia;
	unsigned int imn;
} gpio_state;

static struct {
	unsigned int ioout1;
	unsigned int fmask1;
	unsigned int bmask1;
	unsigned int fmask3;
	unsigned int bmask3;
	unsigned int detmod3;
} pwc_state;

#if ENABLE_FRAMECACHE
static struct {
	unsigned int fif_fcctrl;
	unsigned int fif_frameaaddr;
	unsigned int fif_framebaddr;
	unsigned int fif_framesize;
	unsigned int fif_fcbaseaddr;
} fif_state;
#endif /* ENABLE_FRAMECACHE */


static struct {
	unsigned int smu_ahbclkctrl0;
	unsigned int smu_ahbclkctrl1;
	unsigned int smu_apbclkctrl;
	unsigned int smu_clkctrl;
} clkctrl_state;

static struct {
	unsigned int smu_gio_int_clk_sel;
} smu_state;

#ifdef CONFIG_MP201_RSTRESUME
static struct {
	unsigned int smu_gclkctrl0;
	unsigned int smu_gclkctrl1;
	unsigned int smu_gclkctrl2;
} clock_state;

static struct {
	unsigned int smu_resetreq1a;
	unsigned int smu_resetreq1b;
	unsigned int smu_resetreqdsp;
} reset_state;
#endif

#ifdef CONFIG_MP200_WATCHDOG
static unsigned int smu_wdt_int_reset;
#endif

static unsigned int mp200_sleep_mode = PM_SLEEP_MODE_NONE;
static unsigned int mp200_pctl_uart;

/*
 * Let's power down on idle, but only if we are really
 * idle, because once we start down the path of
 * going idle we continue to do idle even if we get
 * a clock tick interrupt . . 
 */
static void mp200_pm_idle(void)
{
	local_irq_disable();
	local_fiq_disable();

	if (need_resched() == 0) {
        
        /* 2006.07.10 ish : to test CPU load (GPO8=Lo) */
        //outl(0x01000000, SMU_SMU_GPO);

        cpu_do_idle();

        /* 2006.07.10 ish : to test CPU load (GPO8=Hi) */
        //outl(0x01000100, SMU_SMU_GPO);
        
	}

	local_fiq_enable();
	local_irq_enable();
}

static int mp200_pm_set_pmu_cmds(unsigned int cnt, const unsigned int data[], int size)
{
	int i;

	for (i = 0; i < size; i++) {
		outl(data[i],
		     PMU_CMD_BUF_RAM + (cnt + i) * sizeof(unsigned int));
	}

	return i;
}

/*
 * mp200_pm_set_pmu_regs(unsigned int mode)
 */
static void mp200_pm_set_pmu_regs(unsigned int mode)
{
	unsigned int pow_on_pc;
	unsigned int n = 0;

	/* setting pmu command */
	switch(mode){
	case PM_SLEEP_MODE_S1:
		n += SET_PMU_CMDS(n, pmu_cmds_s1_suspend);
		break;
	case PM_SLEEP_MODE_S2:
		n += SET_PMU_CMDS(n, pmu_cmds_s2_suspend);
		break;
	case PM_SLEEP_MODE_S3:
#ifdef PM_POWERIC_ES_SWITCH
		if(lsiver_old)
			n += SET_PMU_CMDS(n, pmu_cmds_s3_suspend_es1_1);
		else
			n += SET_PMU_CMDS(n, pmu_cmds_s3_suspend);
#else
		n += SET_PMU_CMDS(n, pmu_cmds_s3_suspend);
#endif /* PM_POWERIC_ES_SWITCH */
		break;
	}
	pow_on_pc = n;
    
	switch(mode){
	case PM_SLEEP_MODE_S1:
		n += SET_PMU_CMDS(n, pmu_cmds_s1_resume);
		break;
	case PM_SLEEP_MODE_S2:
		n += SET_PMU_CMDS(n, pmu_cmds_s2_resume);
		break;
	case PM_SLEEP_MODE_S3:
#ifdef PM_POWERIC_ES_SWITCH
		if(lsiver_old)
			n += SET_PMU_CMDS(n, pmu_cmds_s3_resume_es1_1);
		else
			n += SET_PMU_CMDS(n, pmu_cmds_s3_resume);
#else
		n += SET_PMU_CMDS(n, pmu_cmds_s3_resume);
#endif /* PM_POWERIC_ES_SWITCH */
		break;
	}
	if (n >= PMU_CMD_BUF_RAM_SIZE) {
		printk(KERN_INFO "%s(): PMU command length over. (%d word)\n",
		       __FUNCTION__, n);
	}

	/* setting pmu regs. */
	/* power off sequence start address */
	outl(0, PMU_PC);

	/* power on sequence start address */
	outl(pow_on_pc, PMU_POWER_ON_PC);

	/* disable watch dog timer */
	outl(PMU_WDT_DISABLE, PMU_WDT_COUNT_EN);

	/* set watch dog timer limit count */
	outl(PMU_WDT_MAX_COUNT, PMU_WDT_COUNT_LMT);
}

static int mp200_pm_intc_mask(int mask, struct intc_state *state)
{
	if (state == 0) {
		return -EINVAL;
	}

	switch (mask) {
	case PM_INTC_MASK_SAVE_AND_MASK:
		state->mask0 = inl(intc[0].imn);
		state->mask1 = inl(intc[1].imn);
		outl(MASK_INTC_ALL, intc[0].ids);
		outl(MASK_INTC_ALL, intc[1].ids);
		break;
	case PM_INTC_MASK_RESTORE:
		outl(MASK_INTC_ALL, intc[0].ids);
		outl(MASK_INTC_ALL, intc[1].ids);
		outl(state->mask0, intc[0].ien);
		outl(state->mask1, intc[1].ien);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static void mp200_pm_save_state(unsigned int mode)
{
	/* save GPIO state */
	gpio_state.imn = inl(VA_GIO + GPIO0_IMN);
	gpio_state.ia = inl(VA_GIO + GPIO0_IA);

/* 2006.05.23 ish
   GPIO state will be restored in each driver, if needed.
*/
#ifndef CONFIG_SONY_ICX1087 

	/* save PWC state */
	pwc_read(PWC_FMASK1, &pwc_state.fmask1);
	pwc_read(PWC_BMASK1, &pwc_state.bmask1);
	pwc_read(PWC_IOOUT1, &pwc_state.ioout1);
    
#ifdef PM_POWERIC_ES_SWITCH
	if(lsiver_old == 0) {
		pwc_read(PWC_FMASK3, &pwc_state.fmask3);
		pwc_read(PWC_BMASK3, &pwc_state.bmask3);
		pwc_read(PWC_DETMOD3H, &pwc_state.detmod3);
	}
#else
	pwc_read(PWC_FMASK3, &pwc_state.fmask3);
	pwc_read(PWC_BMASK3, &pwc_state.bmask3);
	pwc_read(PWC_DETMOD3H, &pwc_state.detmod3);
#endif /* !PM_POWERIC_ES_SWITCH */

#endif


#if ENABLE_FRAMECACHE
	/* save FIFO state */
	fif_state.fif_frameaaddr = inl(FIF_FRAMEAADDR);
	fif_state.fif_framebaddr = inl(FIF_FRAMEBADDR);
	fif_state.fif_framesize = inl(FIF_FRAMESIZE);
	fif_state.fif_fcbaseaddr = inl(FIF_FCBASEADDR);
	fif_state.fif_fcctrl = inl(FIF_FCCTRL);
#endif /* ENABLE_FRAMECACHE */

#ifdef CONFIG_MP201_RSTRESUME
	/* save clockgate status */
	clock_state.smu_gclkctrl0 = inl(SMU_GCLKCTRL0);
	clock_state.smu_gclkctrl1 = inl(SMU_GCLKCTRL1);
	clock_state.smu_gclkctrl2 = inl(SMU_GCLKCTRL2);
	/* save reset status */
	reset_state.smu_resetreq1a = inl(SMU_RESETREQ1A);
	reset_state.smu_resetreq1b = inl(SMU_RESETREQ1B);
	reset_state.smu_resetreqdsp = inl(SMU_RESETREQDSP);
#endif

#ifdef CONFIG_MP200_WATCHDOG
	/* save SMU wdt int reset state */
	smu_wdt_int_reset = inl(SMU_WDT_INT_RESET);
	/* SMU wdt int reset : enable TW0 */
	outl(SMU_TW0_RSTREQ, SMU_WDT_INT_RESET);
#endif

	/* SMU other state */
	smu_state.smu_gio_int_clk_sel = inl(SMU_GIO_INT_CLK_SEL);
	/* gio int use RTC */
	outl(SMU_GIO_INT_CLK_RTC, SMU_GIO_INT_CLK_SEL);

	/* save SMU clkctrl state */
	clkctrl_state.smu_ahbclkctrl0 = inl(SMU_AHBCLKCTRL0);
	clkctrl_state.smu_ahbclkctrl1 = inl(SMU_AHBCLKCTRL1);
	clkctrl_state.smu_apbclkctrl = inl(SMU_APBCLKCTRL);
	clkctrl_state.smu_clkctrl = inl(SMU_CLKCTRL);
	
	/* save SMU PCTRL_C1 */
	mp200_pctl_uart = inl(SMU_PCTL_C1);
	
	return;
}

static void mp200_pm_restore_state(void)
{

	/* restore SMU PCTRL_C1 (use uart) */
	outl(mp200_pctl_uart, SMU_PCTL_C1);
	
#ifdef CONFIG_MP201_RSTRESUME
	/* restore clockgate status */
	outl(clock_state.smu_gclkctrl0, SMU_GCLKCTRL0_ENA);
	outl(clock_state.smu_gclkctrl0, SMU_GCLKCTRL0);
	outl(0, SMU_GCLKCTRL0_ENA);
	outl(clock_state.smu_gclkctrl1, SMU_GCLKCTRL1_ENA);
	outl(clock_state.smu_gclkctrl1, SMU_GCLKCTRL1 );
	outl(0, SMU_GCLKCTRL1_ENA);
	outl(clock_state.smu_gclkctrl2, SMU_GCLKCTRL2_ENA);
	outl(clock_state.smu_gclkctrl2, SMU_GCLKCTRL2 );
	outl(0, SMU_GCLKCTRL2_ENA);
	/* resotre reset status */
	outl(reset_state.smu_resetreq1a, SMU_RESETREQ1A_ENA)
	outl(reset_state.smu_resetreq1a, SMU_RESETREQ1A);
	outl(0, SMU_RESETREQ1A_ENA);
	outl(reset_state.smu_resetreq1b, SMU_RESETREQ1B_ENA
	outl(reset_state.smu_resetreq1b, SMU_RESETREQ1B);
	outl(0, SMU_RESETREQ1B_ENA);
	outl(reset_state.smu_resetreqdsp, SMU_RESETREQDSP_ENA);
	outl(reset_state.smu_resetreqdsp, SMU_RESETREQDSP);
	outl(0, SMU_RESETREQDSP_ENA);
#endif

	/* SMU clkctrl : PB0LP,PB1LP off */
	outl(inl(SMU_AHBCLKCTRL1) & ~(SMU_CLKCTRL_PB0LP | SMU_CLKCTRL_PB1LP),
	     SMU_AHBCLKCTRL1);
	/* restore SMU clkctrl state */
	outl(clkctrl_state.smu_clkctrl, SMU_CLKCTRL);
	outl(clkctrl_state.smu_apbclkctrl, SMU_APBCLKCTRL);
	outl(clkctrl_state.smu_ahbclkctrl1, SMU_AHBCLKCTRL1);
	outl(clkctrl_state.smu_ahbclkctrl0, SMU_AHBCLKCTRL0);
	/* SMU other state */
	outl(smu_state.smu_gio_int_clk_sel, SMU_GIO_INT_CLK_SEL);

#ifdef CONFIG_MP200_WATCHDOG
	/* restore SMU wdt int reset state */
	outl(smu_wdt_int_reset, SMU_WDT_INT_RESET);
#endif

#if ENABLE_FRAMECACHE
	/* restore FIFO state */
	outl(fif_state.fif_frameaaddr, FIF_FRAMEAADDR);
	outl(fif_state.fif_framebaddr, FIF_FRAMEBADDR);
	outl(fif_state.fif_framesize, FIF_FRAMESIZE);
	outl(fif_state.fif_fcbaseaddr, FIF_FCBASEADDR);
	outl(fif_state.fif_fcctrl, FIF_FCCTRL);
#endif /* ENABLE_FRAMECACHE */


	/* uWire state : enable */
	mp200_pm_set_uwire_clock();

/* 2006.12.04 has */
#ifdef CONFIG_SONY_ICX1087
	pwc_write(PWC_WAKECONT, 0, MASK_WAKECONT_WAKEWAIT);
#endif

/* 2006.05.24 ish */    
#ifdef CONFIG_SONY_ICX1087
    unsigned int nFactor1 = 0;
    unsigned int nFactor3 = 0;
    int nCode = 0;
    int nTmpCode = 0;         
         
    /* GPIO */
	pwc_read(PWC_FACTOR1, &nFactor1);
    /* VBUS, RTC etc */
	pwc_read(PWC_FACTOR3, &nFactor3);

    printk(KERN_INFO "*** Resume Factor nFactor1=0x%02x, nFactor3=0x%02x *** \n",
           nFactor1, nFactor3);

    nTmpCode = sonykpd_get_code(nFactor1);
         
    /* checks Hold_Key and AD_Key */
    if (nFactor1 & 0x03) {
        nCode = nTmpCode;
    } else if (nFactor1 & 0x80) {
        /* PWIC_GPIO07 = Cradle */
        /* NOTE: We assumed that PWOFINT is not used */
        nCode += (0x08 << 8);
    } else if (nFactor1 & 0x10) {
        /* EPSON_USB_WAKEUP (PWIC_GPIO4) for EPSON */
        if (_n_usb_suspend) {
            nCode += 0x1000;
        } else {
            /* NOTE: maps to VBUS */
            nCode += 0x8000;
        }
    }
         
    if (nFactor3) {
        nCode += (nFactor3 << 8);
    }

    printk(KERN_INFO "*** Resume Code nCode=0x%04x *** \n", nCode);
         
#ifdef CONFIG_MP200_PM_EXT
    mp200_pm_ext_notify(nCode);
#endif    

#endif  /* CONFIG_SONY_ICX1087 */


         
/* 2006.05.23 ish :
   GPIO state will be restored in each driver, if needed.
*/
#ifndef CONFIG_SONY_ICX1087 
	/* restore PWC state */
	pwc_write(PWC_FMASK1, pwc_state.fmask1, MASK_GPIO_KEYSCAN);
	pwc_write(PWC_CLRFACT1, MASK_GPIO_KEYDATA, MASK_GPIO_KEYDATA);
	pwc_write(PWC_BMASK1, pwc_state.bmask1, MASK_GPIO_KEYSCAN);
	pwc_write(PWC_IOOUT1, pwc_state.ioout1, MASK_GPIO_KEYSCAN);
         
	/* USBWAKE INT state */
#ifdef PM_POWERIC_ES_SWITCH
	if(lsiver_old == 0) {
		pwc_write(PWC_DETMOD3H, pwc_state.detmod3, MASK_DETMODE3H_USBWKM);
		pwc_write(PWC_FMASK3, pwc_state.fmask3, MASK_USBWAKINT);
		pwc_write(PWC_BMASK3, pwc_state.bmask3, MASK_USBWAKINT);
	}
#else
	pwc_write(PWC_DETMOD3H, pwc_state.detmod3, MASK_DETMODE3H_USBWKM);
	pwc_write(PWC_FMASK3, pwc_state.fmask3, MASK_USBWAKINT);
	pwc_write(PWC_BMASK3, pwc_state.bmask3, MASK_USBWAKINT);
#endif /* !PM_POWERIC_ES_SWITCH */

#endif

	/* restore GPIO state */
	outl(gpio_state.ia, VA_GIO + GPIO0_IA);
	outl(MASK_GPIO_ALL, VA_GIO + GPIO0_IME);
	outl(~gpio_state.imn, VA_GIO + GPIO0_IMN);

	return;
}


/*
 * mp200_pm_do_suspend(unsigned int mode)
 */
static void mp200_pm_do_suspend(unsigned int mode)
{
	unsigned int sus_add;
	unsigned int regval;
	void (*suspend_on_sram) (void);

	mp200_pm_save_state(mode);

	/* floating uart pin */
	outl((mp200_pctl_uart & ~0x00000001), SMU_PCTL_C1);

	/* on SRAM mp200_cpu_suspend() */
	sus_add =
	    (unsigned int)mp200_cpu_suspend - (unsigned int)warmboot_handler;
	suspend_on_sram = (void (*)(void))(WARMBOOT_ADDR + sus_add);

	/* WAKEWAIT disable */
	if (mode == PM_SLEEP_MODE_S3) {
		pwc_write(PWC_WAKECONT, WAKECONT_WAKEWAIT_DISABLE, 
			  MASK_WAKECONT_WAKEWAIT);
	}

/* 2006.12.20 has */
#ifdef CONFIG_SONY_ICX1087
	/* wait for RTC Sync */
	udelay(150);
#endif

/* 2006.05.19 ish */
#ifndef CONFIG_SONY_ICX1087 

    /* open key interrupt mask */
	/* PWC */
	pwc_write(PWC_FMASK1, MASK_GPIO_KEYDATA, MASK_GPIO_KEYDATA);
	pwc_write(PWC_CLRFACT1, MASK_GPIO_KEYDATA, MASK_GPIO_KEYDATA);
	pwc_write(PWC_BMASK1, MASK_GPIO_KEYDATA, MASK_GPIO_KEYDATA);
	pwc_write(PWC_IOOUT1, MASK_GPIO_RESUME_KEY, MASK_GPIO_KEYSCAN);
    
	/* USB WAKINT enable */
#ifdef PM_POWERIC_ES_SWITCH
	if(lsiver_old == 0) {
		pwc_write(PWC_FMASK3, MASK_USBWAKINT, MASK_USBWAKINT);
		pwc_write(PWC_DETMOD3H, DETMODE3H_USBWKM_RISE, MASK_DETMODE3H_USBWKM);
		pwc_write(PWC_CLRFACT3, MASK_USBWAKINT, MASK_USBWAKINT);
		pwc_write(PWC_BMASK3, MASK_USBWAKINT, MASK_USBWAKINT);
	}
#else
	pwc_write(PWC_FMASK3, MASK_USBWAKINT, MASK_USBWAKINT);
	pwc_write(PWC_DETMOD3H, DETMODE3H_USBWKM_RISE, MASK_DETMODE3H_USBWKM);
	pwc_write(PWC_CLRFACT3, MASK_USBWAKINT, MASK_USBWAKINT);
	pwc_write(PWC_BMASK3, MASK_USBWAKINT, MASK_USBWAKINT);
#endif /* !PM_POWERIC_ES_SWITCH */

#endif

	/* GPIO */
	outl(MASK_GPIO_ALL, VA_GIO + GPIO0_IME);
	outl((inl(VA_GIO + GPIO0_IA) | MASK_GPIO_RESUME), 
	     VA_GIO + GPIO0_IA);
	outl(MASK_GPIO_RESUME, VA_GIO + GPIO0_IR);
	outl(MASK_GPIO_RESUME, VA_GIO + GPIO0_IMN);

/* 2006.08.25 ishi */
#ifdef CONFIG_SONY_ICX1087 
    /* 2006.06.27 ish : PWC_GPIO10 is used for DETUSB, RTCINT */
    /* These are work-around code for MP201ES1.0 */
    if (lsiver_old) {
        pwc_write(PWC_FMASK2, 0x04, 0x04);
        pwc_write(PWC_REGRSTMSK2, 0x04, 0x04);
    }
#endif

    
    /* setting pmu registers */
	mp200_pm_set_pmu_regs(mode);

	outl(SMU_RESET_STATE_WARM, SMU_SMU_RESET_STATE);

	/* disable uwire int */
	outl(MWI_ENCLR, MWI_INTENCLR);

	/* start PMU */
	outl(PMU_START_SET, PMU_START);

	/* wait for pmu_start */
	do {
		regval = inl(PMU_START);
	} while (regval != PMU_START_SET);

	/* save PEn regs and wait for interrupt */
	suspend_on_sram();

	/*
	 * PEn status moves to WFI, pmu command start at that time.
	 * after warm boot handler done, pc return here
	 */

	regval = inl(PMU_START);
	if ((regval & PMU_START_SET) == PMU_START_SET) {
		outl(0, PMU_START);
		printk(KERN_INFO "%s(): PMU not run.\n", __FUNCTION__);
	}
}

/*
 * mp200_pm_do_resume()
 */
static void mp200_pm_do_resume(void)
{
	outl(SMU_RESET_STATE_CLR, SMU_SMU_RESET_STATE);
	mp200_pm_restore_state();
}

static void mp200_pm_suspend(suspend_state_t state)
{
	struct intc_state intc_state;
	unsigned int sleep_mode;
	unsigned int pll_mode;	
#ifdef CONFIG_MP200_RTC
	struct rtc_time rt;
	long rtc_offset;
	unsigned long mkt;
	extern void get_rtc_time(struct rtc_time *);
#endif

    /* 2006.05.19 ish */
    printk(KERN_INFO "%s() \n", __FUNCTION__);
    
	if (mp200_sleep_mode == PM_SLEEP_MODE_NONE) {
		switch (state) {
		case PM_SUSPEND_STANDBY:
			sleep_mode = PM_SLEEP_MODE_S1;
			break;
		case PM_SUSPEND_MEM:
			sleep_mode = PM_SLEEP_MODE_S3;
			break;
		default:
			return;
		}
	} else {
		sleep_mode = mp200_sleep_mode;
	}

	printk(KERN_INFO "PM: mp200/%x is entering sleep now ...\n",
	       system_rev);

	local_irq_disable();
	local_fiq_disable();

#ifdef CONFIG_MP200_RTC
	/*
	 * lets figure out the offset of the RTC to our system time.
	 */
	memset(&rt, 0, sizeof(struct rtc_time));
	get_rtc_time(&rt);
	mkt = mktime(rt.tm_year + 1900, rt.tm_mon + 1, rt.tm_mday, rt.tm_hour,
		     rt.tm_min, rt.tm_sec);
	rtc_offset = (long)(xtime.tv_sec - mkt);
#endif

	mp200_pm_intc_mask(PM_INTC_MASK_SAVE_AND_MASK, &intc_state);

	timer_set_clock(TIMER_SUSPEND);
	/* if clock is not 12MHz, then make the clock 12MHz */
	pll_mode = mp200_pm_get_pll();
	if(pll_mode != MP200_PLL_12MHZ) {
		mp200_pm_full_to_eco();
	}

	mp200_pm_do_suspend(sleep_mode);
	mp200_pm_do_resume();

	if(pll_mode == MP200_PLL_12MHZ) {
		mp200_pm_full_to_eco();
	}
	else {
		mp200_pm_eco_to_full(pll_mode);
	}
	mp200_pm_update_lpj();

	timer_set_clock(TIMER_RESUME);

	mp200_pm_intc_mask(PM_INTC_MASK_RESTORE, &intc_state);

#ifdef CONFIG_MP200_RTC
	get_rtc_time(&rt);
	mkt = mktime(rt.tm_year + 1900, rt.tm_mon + 1, rt.tm_mday, rt.tm_hour,
		     rt.tm_min, rt.tm_sec);
	xtime.tv_sec = mkt + rtc_offset;
#endif

	local_fiq_enable();
	local_irq_enable();

	printk(KERN_INFO "PM: mp200/%x is re-starting from sleep...\n",
	       system_rev);
}

static void
mp200_pm_set_poweroff_regs(void)
{
	unsigned int n = 0;

	/* power OFF */
	n += SET_PMU_CMDS(n, pmu_cmds_power_off);
	if (n >= PMU_CMD_BUF_RAM_SIZE) {
		printk(KERN_INFO "%s(): PMU command length over. (%d word)\n",
			__FUNCTION__, n);
	}
	/* setting pmu regs. */
	/* power off sequence start address */
	outl(0, PMU_PC);

	/* disable watch dog timer */
	outl(PMU_WDT_DISABLE, PMU_WDT_COUNT_EN);

	/* set watch dog timer limit count */
	outl(PMU_WDT_MAX_COUNT, PMU_WDT_COUNT_LMT);
}


static void
mp200_pm_do_poweroff(void)
{
	unsigned int wfi_reg = 0;
	unsigned int regval;

    /* 2006.08.25 ish */
#ifndef CONFIG_SONY_ICX1087
	/* LCD panel off */
	pwc_write(PWC_IOOUT2, 0x0, MASK_GPIO_LCDPANEL);
#endif
    
	/* setting pmu registers for poweroff */
	mp200_pm_set_poweroff_regs();

	/* disable interrupt */
	outl(MASK_INTC_ALL, intc[0].ids);
	outl(MASK_INTC_ALL, intc[1].ids);

#if 1
	/* mwi APB clock control off */
	outl(inl(SMU_APBCLKCTRL) & ~(0x00040000), SMU_APBCLKCTRL);
#endif
	/* disable uwire int */
	outl(MWI_ENCLR, MWI_INTENCLR);

	/* start PMU */
	outl(PMU_START_SET, PMU_START);

	/* wait for pmu_start */
	do {
		regval = inl(PMU_START);
	} while (regval != PMU_START_SET);

	/* save PEn regs and wait for interrupt */

	__asm__ __volatile__ (" mcr   p15, 0, %0, c7, c0, 4"::"r" (wfi_reg));

	/*
	 * PEn status moves to WFI, pmu command start at that time.
	 * after warm boot handler done, pc return here
	 */
	regval = inl(PMU_START);
	if ((regval & PMU_START_SET) == PMU_START_SET) {
		outl(0, PMU_START);
		printk(KERN_INFO "%s(): PMU not run.\n", __FUNCTION__);
	}
}

void mp200_pm_power_off(void)
{
	unsigned long irq_flags;

    /* 2006.05.19 ish */
    printk(KERN_INFO "\n%s() \n", __FUNCTION__);

	/* int mask */
	local_irq_save(irq_flags);

	/* noneed? */
	timer_set_clock(TIMER_SUSPEND);
	/* if clock is not 12MHz, then make the clock 12MHz */
	if (mp200_pm_get_pll() != MP200_PLL_12MHZ) {
		mp200_pm_full_to_eco();
	}

	/* poweroff setting function*/
	mp200_pm_do_poweroff();

	printk(KERN_INFO "%s(): AFTER PMU POWER OFF.\n", __FUNCTION__);
	/* int unmask */
	local_irq_restore(irq_flags);     /* not call */
}

void mp200_pm_cache_clean(void)
{
	flush_cache_all();
}

static int mp200_pm_prepare(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_STANDBY:
	case PM_SUSPEND_MEM:
		break;

	case PM_SUSPEND_DISK:
		return -ENOTSUPP;

	default:
		return -EINVAL;
	}

	return 0;
}

static int mp200_pm_enter(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_STANDBY:
	case PM_SUSPEND_MEM:
		mp200_pm_suspend(state);
		break;

	case PM_SUSPEND_DISK:
		return -ENOTSUPP;

	default:
		return -EINVAL;
	}

	return 0;
}

static int mp200_pm_finish(suspend_state_t state)
{
	return 0;
}

static struct pm_ops mp200_pm_ops = {
	.pm_disk_mode = 0,
	.prepare = mp200_pm_prepare,
	.enter = mp200_pm_enter,
	.finish = mp200_pm_finish,
};


/* 2006.09.13 ish */
#ifdef CONFIG_SONY_ICX1087

/**
 *
 */
int mp200_pm_get_usb_suspend_state(void)
{
    printk(KERN_DEBUG "*** mp200_pm_get_usb_suspend_state() nRet=%d ***\n", _n_usb_suspend);
    return _n_usb_suspend;
}


/**
 *
 */
int mp200_pm_usb_suspend(void)
{
	suspend_state_t state;
	int ret;

    /* 2006.07.10 : test (GPO8=Hi) */
    //outl(0x01000100, SMU_SMU_GPO);
    
    printk(KERN_DEBUG "*** mp200_pm_usb_suspend() ***\n");

    /* 2006.07.10 : test (GPO8=Lo) */
    //outl(0x01000000, SMU_SMU_GPO);

    _n_usb_suspend = 1;
    
    state = PM_SUSPEND_MEM;
	mp200_sleep_mode = PM_SLEEP_MODE_S3;
	ret = pm_suspend(state);
	mp200_sleep_mode = PM_SLEEP_MODE_NONE;
	return ret;
}

#endif  /* CONFIG_SONY_ICX1087 */


int mp200_pm_sleep(unsigned int mode)
{
	suspend_state_t state;
	int ret;

/* 2006.09.13 ish */
#ifdef CONFIG_SONY_ICX1087
    printk("*** mp200_pm_sleep() ***\n");
    _n_usb_suspend = 0;
#endif
    
	switch (mode) {
	case PM_SLEEP_MODE_S1:
	case PM_SLEEP_MODE_S2:
		state = PM_SUSPEND_STANDBY;
		break;
	case PM_SLEEP_MODE_S3:
		state = PM_SUSPEND_MEM;
		break;
	default:
		return -EINVAL;
	}

	mp200_sleep_mode = mode;
	ret = pm_suspend(state);
	mp200_sleep_mode = PM_SLEEP_MODE_NONE;

	return ret;
}

#ifdef CONFIG_PROC_FS
/*
 * Writing to /proc/pm puts the CPU in sleep mode
 */
static ssize_t mp200_pm_write_proc(struct file *file, const char *buffer,
				   size_t count, loff_t * ppos)
{
	char *buf;
	char *tok;
	char *s;
	char *str;
	char *whitespace = " \t\r\n";
	int ret = 0;

	if (current->uid != 0) {
		return -EPERM;
	}
	if (count == 0) {
		return 0;
	}
	buf = kmalloc(count + 1, GFP_KERNEL);
	if (buf == NULL) {
		ret = -ENOMEM;
		goto exit_2;
	}
	if (copy_from_user(buf, buffer, count) != 0) {
		ret = -EFAULT;
		goto exit_1;
	}
	buf[count] = '\0';
	s = buf + strspn(buf, whitespace);
	tok = strsep(&s, whitespace);

	str = "M248";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("248MHz...\n");
		ret = mp200_pm_set_pll(MP200_PLL_248MHZ);
		goto exit_1;
	}
    
/* 2006.06.27 ish : M164 is not used. */
#ifndef CONFIG_SONY_ICX1087
	str = "M164";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("164MHz...\n");
		ret = mp200_pm_set_pll(MP200_PLL_164MHZ);
		goto exit_1;
	}
#endif
    
	str = "M124";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("124MHz...\n");
		ret = mp200_pm_set_pll(MP200_PLL_124MHZ);
		goto exit_1;
	}
	str = "M83";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("83MHz...\n");
		ret = mp200_pm_set_pll(MP200_PLL_83MHZ);
		goto exit_1;
	}
	str = "M50";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("50MHz...\n");
		ret = mp200_pm_set_pll(MP200_PLL_50MHZ);
		goto exit_1;
	}

	str = "M12";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("12MHz(OSC)...\n");
		ret = mp200_pm_set_pll(MP200_PLL_12MHZ);
		goto exit_1;
	}

/* 2006.06.27 ish : S1 and S2 are not used. */
#ifndef CONFIG_SONY_ICX1087
	str = "S1";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		ret = mp200_pm_sleep(PM_SLEEP_MODE_S1);
		goto exit_1;
	}
	str = "S2";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		ret = mp200_pm_sleep(PM_SLEEP_MODE_S2);
		goto exit_1;
	}
#endif
    
	str = "S3";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		ret = mp200_pm_sleep(PM_SLEEP_MODE_S3);
		goto exit_1;
	}

/* 2006.07.13 ish : PD is not used anymore. */
#ifndef CONFIG_SONY_ICX1087
	str = "PD";
	if (strnicmp(tok, str, strlen(str) + 1) == 0) {
		printk("MP201 PowerDown...\n");
		mp200_pm_power_off();
		goto exit_1;
	}
#endif

    /* 2006.07.13 ish */
    printk("PM: %s is not supported. \n", tok);

	ret = -EINVAL;

      exit_1:
	kfree(buf);
      exit_2:
	if (ret == 0) {
		return count;
	}

	return ret;
}

static int mp200_pm_read_proc(char *page, char **start, off_t off, int count,
			      int *eof, void *data)
{
#ifdef PM_DEBUG_REG
	printk("** SMU registers dump ** \n");
	printk("SMU_SMU_RESET_STATE = 0x%08x \n", inl(SMU_SMU_RESET_STATE));
	printk("SMU_PLLSEL          = 0x%08x \n", inl(SMU_PLLSEL));
	printk("SMU_PLLSEL2         = 0x%08x \n", inl(SMU_PLLSEL2));
	printk("SMU_LPLL_CTRL1      = 0x%08x \n", inl(SMU_LPLL_CTRL1));
	printk("SMU_LPLL_CTRL2      = 0x%08x \n", inl(SMU_LPLL_CTRL2));
	printk("SMU_HPLL_CTRL1      = 0x%08x \n", inl(SMU_HPLL_CTRL1));
	printk("SMU_HPLL_CTRL2      = 0x%08x \n", inl(SMU_HPLL_CTRL2));
	printk("SMU_HPLL_CTRL3      = 0x%08x \n", inl(SMU_HPLL_CTRL3));
	printk("SMU_HPLL_CTRL4      = 0x%08x \n", inl(SMU_HPLL_CTRL4));
	printk("SMU_CLK_DOMAIN_DIV  = 0x%08x \n", inl(SMU_CLK_DOMAIN_DIV));
	printk("SMU_OSC_CTRL        = 0x%08x \n", inl(SMU_OSC_CTRL));
	printk("SMU_AUTO_FRQ_CHANGE = 0x%08x \n", inl(SMU_AUTO_FRQ_CHANGE));

	printk("** FIF registers dump ** \n");
	printk("FIF_SDRCONFIGA      = 0x%08x \n", inl(FIF_SDRCONFIGA));
	printk("FIF_SDRCONFIGB      = 0x%08x \n", inl(FIF_SDRCONFIGB));

	printk("\n");
	printk("loops_per_jiffy     = 0x%08x \n", (unsigned int)loops_per_jiffy);
#endif /* PM_DEBUG_REG */

	return 0;
}

#endif				/* CONFIG_PROC_FS */

extern void (*mp200_change_pll_on_sram) (struct pll_param *);
extern void (*mp200_change_osc_on_sram) (void);

static int __init mp200_pm_init(void)
{
#ifdef CONFIG_PROC_FS
	struct proc_dir_entry *entry;
#endif
#ifdef PM_POWERIC_ES_SWITCH
	unsigned int reg = 0;
#endif

	printk(KERN_INFO "Starting pm.\n");

#ifdef PM_POWERIC_ES_SWITCH
	if(pwc_read(PWC_LSIVER, &reg) < 0) {
		return -EIO;
	}
	printk(KERN_INFO " RW5T735 LSIVER [%02x]\n", reg);

	if(reg <= PWC_LSIVER_ES1_1) {
		lsiver_old = 1; /* ES1.1 or less */
	}
#endif /* PM_POWERIC_ES_SWITCH */

	pm_idle = mp200_pm_idle;

	/*
	 * copy to SRAM
	 */
	if (warmboot_handler_size > (HANDLER_SIZE - 4)) {
		printk(KERN_INFO "warmboot handler size over. 0x%x\n",
		       warmboot_handler_size);
		return -ENOMEM;
	}

	/* copy warm boot handler to SRAM S/W virtual area */
	memcpy((void *)WARMBOOT_ADDR, warmboot_handler, warmboot_handler_size);

	mp200_change_pll_on_sram = 
	    (void (*)(struct pll_param *))(WARMBOOT_ADDR +
	    ((unsigned int)mp200_change_pll - (unsigned int)warmboot_handler));
	mp200_change_osc_on_sram = 
	    (void (*)(void))(WARMBOOT_ADDR +
	    ((unsigned int)mp200_change_osc - (unsigned int)warmboot_handler));
#ifdef PM_DEBUG_REG
	printk("mp200_change_pll_on_sram = 0x%08x \n",
		(unsigned int)mp200_change_pll_on_sram);
	printk("mp200_change_osc_on_sram = 0x%08x \n",
		(unsigned int)mp200_change_osc_on_sram);
#endif /* PM_DEBUG_REG */
	pm_set_ops(&mp200_pm_ops);

#ifdef CONFIG_PROC_FS
	entry = create_proc_read_entry("pm", S_IWUSR | S_IRUGO, NULL,
				       mp200_pm_read_proc, 0);
	if (entry == NULL) {
		return -ENOENT;
	}
	entry->write_proc = (write_proc_t *) mp200_pm_write_proc;
#endif

/* 2006.09.08 ish */
#ifndef CONFIG_SONY_ICX1087 
	/*
	 * set irq type of button (rising edge)
	 */
	set_irq_type(INT_PWC_GPIO_KEY_DATA0, IRQT_RISING);
	set_irq_type(INT_PWC_GPIO_KEY_DATA1, IRQT_HIGH);
	set_irq_type(INT_PWC_GPIO_KEY_DATA2, IRQT_RISING);
	set_irq_type(INT_PWC_GPIO_KEY_DATA3, IRQT_RISING);
	
	/* button (GPIO0-4) chattering On */
	pwc_write(PWC_STATE1, MASK_GPIO_KEYDATA, MASK_GPIO_KEYDATA);
#endif    

	/* USBWAK chattering Off */
#ifdef PM_POWERIC_ES_SWITCH
	if(lsiver_old == 0) {
		pwc_write(PWC_STATE3, 0x00, MASK_USBWAKINT);
	}
#else
	pwc_write(PWC_STATE3, 0x00, MASK_USBWAKINT);
#endif /* !PM_POWERIC_ES_SWITCH */

	pm_power_off = mp200_pm_power_off;

	return 0;
}

__initcall(mp200_pm_init);

EXPORT_SYMBOL(mp200_pm_sleep);

/* 2006.09.13 ish */
#ifdef CONFIG_SONY_ICX1087
EXPORT_SYMBOL(mp200_pm_usb_suspend);
EXPORT_SYMBOL(mp200_pm_get_usb_suspend_state);
#endif
