/*
 * mx51-3stack-pmic-mc13892.c  --  i.MX51 3STACK Driver for Atlas MC13892 PMIC
 */
 /*
  * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
  */

 /*
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
  * Version 2 or later at the following locations:
  *
  * http://www.opensource.org/licenses/gpl-license.html
  * http://www.gnu.org/copyleft/gpl.html
  */
/*---------------------------------------------------------------------------
 * Pegatron Modify History
 *---------------------------------------------------------------------------
 * 2009/10/22  Kevin Wei  - 1. add open WiFi VGEN1 - need 1.5V
 *---------------------------------------------------------------------------
 * 2009/10/27  Eric Chou  - 1. power off when switch power key 4 sec
 *---------------------------------------------------------------------------
 * 2009/11/03  Huimin Lin - 1. modify regulator initial
 *                          2. add green LED - mxc_misc_init()
 *---------------------------------------------------------------------------
 * 2009/11/10  Kevin Wei  - 1. add usb_vbus_power()
 *                          2. pmic_debug_read()
 *---------------------------------------------------------------------------
 * 2009/11/20  Eric Chou  - 1. modify
 *                          2. fine-tune
 *---------------------------------------------------------------------------
 * 2009/12/18  Huimin Lin - 1. add - to support HW USB power control design
 *---------------------------------------------------------------------------
 * 2010/04/24             - 1. add isACadapter().
 *---------------------------------------------------------------------------
 * 2010/04/30             - 1. add isOtgHostMode().
 *---------------------------------------------------------------------------
 * 2010/05/14             - 1. modify - charge start/stop.
 *---------------------------------------------------------------------------
 * 2010/05/19             - 1. modify - change Power-ON when STBY.
 *                                       VGEN1, VGEN2, VGEN3, USB2, VIOHI
 *---------------------------------------------------------------------------
 * 2010/05/28             - 1. modify - change Power-ON when STBY.
 *                                       VIOHI
 *---------------------------------------------------------------------------
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/pmic_external.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/mc13892/core.h>
#include <linux/delay.h> // add by pega Kevin 2009.11.10 - for usb_vbus_power() use mdelay()
#include <mach/arc_otg.h>
#include "iomux.h"

// modify by pega Eric 2009.11.20
#define SET_BOOT_ON_TO_OFF    0


#define DEBUG_TRACE        1
#if ( DEBUG_TRACE )
#define DEBUG_PRINTK(x)    printk x
#else
#define DEBUG_PRINTK(x)
#endif

//Modify by pega Huimin 2009.12.18 to support HW USB power control design
#define DEVICE_USB_HW_DESIGN	1

#if ( 1 ) // add by pega Kevin 2009.10.22 - WiFi VGEN1 - need 1.5V
#define VGEN1_LSH          0
#define VGEN1_WID          2
#define VGEN1_EN_LSH       0
#define VGEN1_EN_WID       1
#define VGEN1_EN_ENABLE    1
#define VGEN1_EN_DISABLE   0
#endif

/*
 * Convenience conversion.
 * Here atm, maybe there is somewhere better for this.
 */
#define mV_to_uV(mV)       (mV * 1000)
#define uV_to_mV(uV)       (uV / 1000)
#define V_to_uV(V)         (mV_to_uV(V * 1000))
#define uV_to_V(uV)        (uV_to_mV(uV) / 1000)

/* Coin cell charger enable */
#define CIONCHEN_LSH       23
#define CIONCHEN_WID       1
/* Coin cell charger voltage setting */
#define VCOIN_LSH          20
#define VCOIN_WID          3

/* Coin Charger voltage */
#define VCOIN_2_5V         0x0
#define VCOIN_2_7V         0x1
#define VCOIN_2_8V         0x2
#define VCOIN_2_9V         0x3
#define VCOIN_3_0V         0x4
#define VCOIN_3_1V         0x5
#define VCOIN_3_2V         0x6
#define VCOIN_3_3V         0x7

/* Keeps VSRTC and CLK32KMCU on for all states */
#define DRM_LSH            4
#define DRM_WID            1

/* regulator standby mask */
#define GEN1_STBY_MASK     (1 << 1)
#define IOHI_STBY_MASK     (1 << 4)
#define DIG_STBY_MASK      (1 << 10)
#define GEN2_STBY_MASK     (1 << 13)
#define PLL_STBY_MASK      (1 << 16)
#define USB2_STBY_MASK     (1 << 19)

#define GEN3_STBY_MASK     (1 << 1)
#define CAM_STBY_MASK      (1 << 7)
#define VIDEO_STBY_MASK    (1 << 13)
#define AUDIO_STBY_MASK    (1 << 16)
#define SD_STBY_MASK       (1 << 19)

/*
 * Power-ON when STBY.
 *  VIOHI
 */
#define REG_MODE_0_ALL_MASK   ( GEN1_STBY_MASK |\
                                DIG_STBY_MASK  | GEN2_STBY_MASK |\
                                PLL_STBY_MASK  | USB2_STBY_MASK )
#define REG_MODE_1_ALL_MASK   ( GEN3_STBY_MASK  | CAM_STBY_MASK   |\
                                VIDEO_STBY_MASK | AUDIO_STBY_MASK |\
                                SD_STBY_MASK )
/* CPU */
static struct regulator_consumer_supply sw1_consumers[] =
{
   {
      .supply = "cpu_vcc",
   }
};

struct mc13892;

#if ( 0 )
static struct regulator_init_data sw1_init =
{
   .constraints =
   {  .name             = "SW1",
      .min_uV           = mV_to_uV(600),            // voltage output range
      .max_uV           = mV_to_uV(1375),           // voltage output range
//    .min_uA           = 0,                        // current output range
//    .man_uA           = 0,                        // current output range
      .valid_modes_mask = 0,                        // valid regulator operating modes
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
//    .input_uV =       = ,                         // regulator input voltage
      .always_on        = 1,                        // regulator never off when system is on
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
//    .apply_uV         = 0,                        // apply uV constraint iff min == max
      .initial_state    = PM_SUSPEND_MEM,           // suspend state to set at init - suspend_state_t : include/linux/suspend.h
//    .state_disk =     // regulator suspend states - PMIC standby / hibernate
//    {  .uV            = 0,                        // suspend voltage
//       .mode          = 0,                        // suspend regulator operating mode
//       .enabled       = 0,                        // enabled in this suspend state
//    },
      .state_mem =      // regulator suspend states - PMIC standby / hibernate
      {  .uV            = 700000,                   // suspend voltage
         .mode          = REGULATOR_MODE_NORMAL,    // suspend regulator operating mode
         .enabled       = 1,                        // enabled in this suspend state
      },
//    .state_standby =  // regulator suspend states - PMIC standby / hibernate
//    {  .uV            = 0,                        // suspend voltage
//       .mode          = 0,                        // suspend regulator operating mode
//       .enabled       = 0,                        // enabled in this suspend state
//    },
   },
   .num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
   .consumer_supplies     = sw1_consumers,
};
#endif

static struct regulator_init_data sw1_init =
{
   .constraints =
   {  .name             = "SW1",
      .min_uV           = mV_to_uV(600),            // voltage output range
      .max_uV           = mV_to_uV(1375),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      .always_on        = 1,                        // regulator never off when system is on
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
      .initial_state    = PM_SUSPEND_MEM,           // suspend state to set at init - suspend_state_t : include/linux/suspend.h
      .state_mem =      // regulator suspend states - PMIC standby / hibernate
      {  .uV            = 700000,                   // suspend voltage
         .mode          = REGULATOR_MODE_NORMAL,    // suspend regulator operating mode
         .enabled       = 1,                        // enabled in this suspend state
      },
   },
   .num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
   .consumer_supplies     = sw1_consumers,
};
static struct regulator_init_data sw2_init =
{
   .constraints =
   {  .name             = "SW2",
      .min_uV           = mV_to_uV(900),            // voltage output range
      .max_uV           = mV_to_uV(1850),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      .always_on        = 1,                        // regulator never off when system is on
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
      .initial_state    = PM_SUSPEND_MEM,           // suspend state to set at init - suspend_state_t : include/linux/suspend.h
      .state_mem =      // regulator suspend states - PMIC standby / hibernate
      {  .uV            = 900000,                   // suspend voltage
         .mode          = REGULATOR_MODE_NORMAL,    // suspend regulator operating mode
         .enabled       = 1,                        // enabled in this suspend state
      },
   },
};
static struct regulator_init_data sw3_init =
{
   .constraints =
   {  .name             = "SW3",
      .min_uV           = mV_to_uV(1100),           // voltage output range
      .max_uV           = mV_to_uV(1850),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      .always_on        = 1,                        // regulator never off when system is on
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
   },
};
static struct regulator_init_data sw4_init =
{
   .constraints =
   {  .name             = "SW4",
      .min_uV           = mV_to_uV(1100),           // voltage output range
      .max_uV           = mV_to_uV(1850),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      .always_on        = 1,                        // regulator never off when system is on
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
   },
};
static struct regulator_init_data viohi_init =
{
   .constraints =
   {  .name             = "VIOHI",
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
   },
};
static struct regulator_init_data vusb_init =
{
   .constraints =
   {  .name             = "VUSB",
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
   },
};
static struct regulator_init_data swbst_init =
{
   .constraints =
   {  .name             = "SWBST",
   },
};
static struct regulator_init_data vdig_init =
{
   .constraints =
   {  .name             = "VDIG",
      .min_uV           = mV_to_uV(1050),           // voltage output range
      .max_uV           = mV_to_uV(1800),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
   },
};
static struct regulator_init_data vpll_init =\
{
   .constraints =
   {  .name             = "VPLL",
      .min_uV           = mV_to_uV(1050),           // voltage output range
      .max_uV           = mV_to_uV(1800),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
   },
};
static struct regulator_init_data vusb2_init =
{
   .constraints =
   {  .name             = "VUSB2",
      .min_uV           = mV_to_uV(2400),           // voltage output range
      .max_uV           = mV_to_uV(2775),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      #if ( SET_BOOT_ON_TO_OFF )
      .boot_on          = 0,                        // bootloader / firmware enabled regulator
      #else
      .boot_on          = 1,                        // bootloader / firmware enabled regulator
      #endif
   },
};
static struct regulator_init_data vvideo_init =
{
   .constraints =
   {  .name             = "VVIDEO",
      .min_uV           = mV_to_uV(2775),           // voltage output range
      .max_uV           = mV_to_uV(2775),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
      .always_on        = 1,                        // regulator never off when system is on
      .apply_uV         = 1,                        // apply uV constraint iff min == max
   },
};

static struct regulator_init_data vaudio_init =
{
   .constraints =
   {  .name             = "VAUDIO",
      .min_uV           = mV_to_uV(2300),           // voltage output range
      .max_uV           = mV_to_uV(3000),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
   },
};

static struct regulator_init_data vsd_init =
{
   .constraints =
   {  .name             = "VSD",
      .min_uV           = mV_to_uV(1800),           // voltage output range
      .max_uV           = mV_to_uV(3150),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
   },
};

static struct regulator_init_data vcam_init =
{
   .constraints =
   {  .name             = "VCAM",
      .min_uV           = mV_to_uV(2500),           // voltage output range
      .max_uV           = mV_to_uV(3000),           // voltage output range
      .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL,
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
   },
};

static struct regulator_init_data vgen1_init =
{
   .constraints =
   {  .name             = "VGEN1",
      .min_uV           = mV_to_uV(1200),           // voltage output range
      .max_uV           = mV_to_uV(3150),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
   },
};

static struct regulator_init_data vgen2_init =
{
   .constraints =
   {  .name             = "VGEN2",
      .min_uV           = mV_to_uV(1200),           // voltage output range
      .max_uV           = mV_to_uV(3150),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
   },
};

static struct regulator_init_data vgen3_init =
{
   .constraints =
   {  .name             = "VGEN3",
      .min_uV           = mV_to_uV(1800),           // voltage output range
      .max_uV           = mV_to_uV(2900),           // voltage output range
      .valid_ops_mask   = REGULATOR_CHANGE_VOLTAGE, // valid operations for regulator
   },
};

static struct regulator_init_data gpo1_init =
{
   .constraints = {  .name = "GPO1", },
};

static struct regulator_init_data gpo2_init =
{
   .constraints = {  .name = "GPO2", },
};

static struct regulator_init_data gpo3_init =
{
   .constraints = {  .name = "GPO3", },
};

static struct regulator_init_data gpo4_init =
{
   .constraints = {  .name = "GPO4", },
};

#if ( SET_BOOT_ON_TO_OFF ) // modify by pega Huimin 2009.11.03 - in order to force resetting the regulator

static struct regulator_post_init
{
   char *name;
   struct regulator *reg;
   int uVoltage;
   int apply_uV;
   int enable;
};

static struct regulator_post_init __initdata regulator_post_init_data[] =
{
   {  .name     = "SW1",
      .uVoltage = mV_to_uV(1050), // VDDGP = 1.05 - CPU
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "SW2",
      .uVoltage = mV_to_uV(1250), // VCC = 1.25 - CPU
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "SW3",
      .uVoltage = mV_to_uV(1250), // 1V2_DIG1 = 1.25 - CPU
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "SW4",
      .uVoltage = mV_to_uV(1800), // 1V8_DIG1 = 1.8 - CPU / UART1 / WiFi / Bluetooth / USB phy
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "SWBST",        // open when use
      .uVoltage = mV_to_uV(5000), // SWBST = 5.0 - USB OTG
      .apply_uV = 1,
      .enable   = 0,
   },
   {  .name     = "VVIDEO",
      .uVoltage = mV_to_uV(2775), // 2V775 = 2.775 - Optical Joystick / Audio
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "VUSB",         // not use
      .uVoltage = mV_to_uV(3300), // 3V3_USB_MX51 = 3.3 - EVT2 DVT not connect
      .apply_uV = 1,
      .enable   = 0,
   },
   {  .name     = "VUSB2",
      .uVoltage = mV_to_uV(2600), // 2V6 = 2.6 - CPU
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "VAUDIO",
      .uVoltage = mV_to_uV(3000), // 3VANA_PMIC = 3.0 - CPU
      .apply_uV = 1,
      .enable   = 1,
   },
   {  .name     = "VIOHI",
      .uVoltage = mV_to_uV(2775), // 2V775_BOOT = 2.775 - CPU / Nor Flash
      .apply_uV = 0,              // not need to setting
      .enable   = 1,
   },
   {  .name      = "VPLL",
      .uVoltage  = mV_to_uV(1800), // 1V8_ANA_PLL = 1.8 - CPU
      .apply_uV  = 1,
      .enable    = 1,
   },
   {  .name      = "VDIG",
      .uVoltage  = mV_to_uV(1650), // 1V65 = 1.65 - Audio
      .apply_uV  = 1,
      .enable    = 1,
   },
   {  .name      = "VCAM",         // not use
      .uVoltage  = mV_to_uV(2800), // 2V8 = 2.8 - camera not connect
      .apply_uV  = 1,
      .enable    = 0,
   },
   {  .name      = "VSD",          // open when use
      .uVoltage  = mV_to_uV(3150), // 3V15 = 3.15 - Vibrator Motor
      .apply_uV  = 1,
      .enable    = 0,
   },
   {  .name      = "VGEN1",
      .uVoltage  = mV_to_uV(1500), // 1V5_DIG2 = 1.5 - WiFi / Bluetooth
      .apply_uV  = 1,
      .enable    = 1,
   },
   {  .name      = "VGEN2",
      .uVoltage  = mV_to_uV(3150), // 3V15_BOOT = 3.15 - CPU / SD / WiFi / Bluetooth / SD
      .apply_uV  = 1,
      .enable    = 1,
   },
   {  .name      = "VGEN3",
      .uVoltage  = mV_to_uV(1800), // 1V8_DIG2 = 1.8 - GPIO level conversion / camera
      .apply_uV  = 1,
      .enable    = 1,
   },
};

#endif
static int mc13892_regulator_init(struct mc13892 *mc13892)
{
   unsigned int value, register_mask;
   int i;

   printk("Initializing regulators for Babbage.\n");

   if ( mxc_cpu_is_rev(CHIP_REV_2_0) < 0 )
      sw2_init.constraints.state_mem.uV = 1100000;
   else if ( mxc_cpu_is_rev(CHIP_REV_2_0) >= 1 )
   {
      sw2_init.constraints.state_mem.uV = 1250000;
      sw1_init.constraints.state_mem.uV = 1000000;
   }

   // enable standby controll for all regulators
   pmic_read_reg(REG_MODE_0, &value, 0xffffff);
   value |= REG_MODE_0_ALL_MASK;
   DEBUG_PRINTK(("REG_MODE_0 = reg %d = %x \n", REG_MODE_0, value));
   pmic_write_reg(REG_MODE_0, value, 0xffffff);

   pmic_read_reg(REG_MODE_1, &value, 0xffffff);
   value |= REG_MODE_1_ALL_MASK;
   DEBUG_PRINTK(("REG_MODE_1 = reg %d = %x \n", REG_MODE_1, value));
   pmic_write_reg(REG_MODE_1, value, 0xffffff);

   // enable coin cell charger
   value = BITFVAL(CIONCHEN, 1) | BITFVAL(VCOIN, VCOIN_3_0V);
   register_mask = BITFMASK(CIONCHEN) | BITFMASK(VCOIN);
   DEBUG_PRINTK(("REG_POWER_CTL0 = reg %d = %x \n", REG_POWER_CTL0, value));
   pmic_write_reg(REG_POWER_CTL0, value, register_mask);

   #if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE)
   value = BITFVAL(DRM, 1);
   register_mask = BITFMASK(DRM);
   pmic_write_reg(REG_POWER_CTL0, value, register_mask);
   #endif

   mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init);
   mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init);
   mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init);
   mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init);
   mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init);
   mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init);
   mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init);
   mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init);
   mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init);
   mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init);
   mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init);
   mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init);
   mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init);
   mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init);
   mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init);
   mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init);
   mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init);
   mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init);
   mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init);
   mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init);
   mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init);

   // modify by pega Huimin 2009.11.03 - in order to force resetting the regulator
   #if ( SET_BOOT_ON_TO_OFF )
   for ( i = 0 ; i < ARRAY_SIZE(regulator_post_init_data) ; i++ )
   {
      if ( regulator_post_init_data[i].reg = regulator_get(NULL, regulator_post_init_data[i].name) )
      {
         // set voltage
         if ( regulator_post_init_data[i].apply_uV )
            regulator_set_voltage(regulator_post_init_data[i].reg,
                                  regulator_post_init_data[i].uVoltage,
                                  regulator_post_init_data[i].uVoltage);
         // set enable
         if ( regulator_post_init_data[i].enable )
            regulator_enable(regulator_post_init_data[i].reg);
         else
            regulator_disable(regulator_post_init_data[i].reg);
      }
   }
   #endif

   #if ( 1 ) // add by pega Kevin 2009.10.22 - WiFi VGEN1 - need 1.5V
   pmic_write_reg(REG_SETTING_0, BITFVAL(VGEN1, 1), BITFMASK(VGEN1));    // REG_SETTING_0 = 30[1:0] = VGEN1 voltage setting
   pmic_write_reg(REG_MODE_0, BITFVAL(VGEN1_EN, 1), BITFMASK(VGEN1_EN)); // REG_MODE_0    = 32[0]   = VGEN1_EN
   #endif

   #if ( 1 ) // add by pega Eric 2009.10.27 - REG_SETTING_0 = 15[1]= PWRON1RSTEN , [5:4] = Set debounce time on PWRON1
   pmic_read_reg(REG_POWER_CTL2, &value, 0xFFFFFF);
   value |= 0x22;
   DEBUG_PRINTK(("REG_POWER_CTL2 = reg %d = %x \n", REG_POWER_CTL2, value));
   pmic_write_reg(REG_POWER_CTL2, value, 0xFFFFFF);
   #endif

   return 0;
}

// add by pega Eric 2009.11.20
// for normal
#define LEDG_N_PERIOD  3   // REG_LED_CTL2 = 53[13:12] = LEDGPER
#define LEDG_N_RAMP    0   // REG_LED_CTL2 = 53[14]    = LEDGRAMP
#define LEDG_N_CYCLE   32  // REG_LED_CTL2 = 53[20:15] = LEDGDC
#define LEDG_N_CURRENT 7   // REG_LED_CTL2 = 53[23:21] = LEDG
// for suspend
#define LEDG_S_PERIOD  3   // max = 3  , 0 = 1/256 , 1 = 1/8 , 2 = 1s , 3 = 2s
#define LEDG_S_RAMP    0   // max = 1  ,
#define LEDG_S_CYCLE   16  // max = 32 , 0 = 0/32 , 1 = 1/32 , 32 = 32/32
#define LEDG_S_CURRENT 4   // max = 7  , 0 = 0 mA , 1 = 3 mA , 4 = 12mA , 7 = 21 mA

// modify by pega Huimin 2009.11.03 - green LED always on when power on
// modify by pega Eric 2009.11.20 - REG_LED_CTL2 = 53[13:12]= LEDGPER , [14] = LEDGRAMP , [15:20] = LEDGDC , [23:21] = LEDG
#if ( 1 )
static int mxc_misc_init(void)
{
   unsigned int value;

// pmic_read_reg(REG_LED_CTL2, &value, 0xFFF000); // only read green LED setting
   value = ( LEDG_N_CURRENT << 21 ) + ( LEDG_N_CYCLE << 15 ) + ( LEDG_N_RAMP << 14 ) + ( LEDG_N_PERIOD << 12 );
   DEBUG_PRINTK(("REG_LED_CTL2 = reg %d = %x \n", REG_LED_CTL2, value));
   pmic_write_reg(REG_LED_CTL2, value, 0xFFF000); // only write green LED setting

   return 0;
}
late_initcall(mxc_misc_init);
#endif

static struct mc13892_platform_data mc13892_plat = {
   .init = mc13892_regulator_init,
};

static struct spi_board_info __initdata mc13892_spi_device = {
   .modalias = "pmic_spi",
   .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_8),
   .max_speed_hz = 1000000,   /* max spi SCK clock speed in HZ */
   .bus_num = 1,
   .chip_select = 0,
   .platform_data = &mc13892_plat,
};


int __init mx51_babbage_init_mc13892(void)
{
   return spi_register_board_info(&mc13892_spi_device, 1);
}

//---------------------------------
// USB OTG is connect AC adapter
//---------------------------------
int isACadapter (void)
{
    /*
     * mini-USB cable   Device       VBUS      USB_ID
     *  discon           none   ->  0(Invalid)  1(Gadget)
     *  connect          none   ->  1(Valid)    0(Host)
     *  connect         connect ->  1(Valid)    0(Host)
     *     PowerCable           ->  1(Valid)    1(Gadget)
     */
    if ((USBOTG_REG32(0x1A4) & (OTGSC_STS_A_VBUS_VALID | OTGSC_STS_USB_ID)) ==
        (OTGSC_STS_A_VBUS_VALID | OTGSC_STS_USB_ID)) {
        return 1;
    }
    return 0;
}

//---------------------------------
// USB OTG is HOST mode.
//---------------------------------
int isOtgHostMode (void)
{
    if ((USBOTG_REG32(0x1A4) & OTGSC_STS_USB_ID) == 0x00000000) {
        return 1;
    }
    return 0;
}

//---------------------------------
// USB OTG VBUS power change
//---------------------------------
// add by pega Kevin 2009.11.10
// modify by pega Eric 2009.11.20
//---------------------------------
void usb_vbus_power(int on)
{
   unsigned int value;
   extern int pmic_battery_start_charge (void);
   extern int pmic_battery_stop_charge (void);

   //----------------------------------------------------------
   // Host mode - MX51 connect USB device ( cable ID = 0 )
   //----------------------------------------------------------
   if ( on )
   {
      //----------------
      // close charging
      //----------------
      pmic_battery_stop_charge ();
      mdelay(10);

//Modify by pega Huimin 2009.12.18 to support HW USB power control design
#if (DEVICE_USB_HW_DESIGN)
	//OTG_EN = 0
	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D16), 0);
	printk("%s:%d\n",__FUNCTION__,on);
	mdelay(10);
#endif

      //----------------
      // open VBUS
      //----------------
      // REG_SW_5 = REG_29[20] = SWBSTEN = 1
      pmic_read_reg(REG_SW_5, &value, 0xFFFFFF);
      value |= 0x100000;
      pmic_write_reg(REG_SW_5, value, 0xFFFFFF);

      // REG_USB1 = REG_50[0] = VUSBIN = 1 , REG_50[10] = OTGSWBSTEN = 1
      pmic_read_reg(REG_USB1, &value, 0xFFFFFF);
      value |= 0x000401;
      pmic_write_reg(REG_USB1, value, 0xFFFFFF);
   }
   //----------------------------------------------------------
   // device mode - MX51 connect to PC ( Host )( cable ID = 1 )
   //----------------------------------------------------------
   else
   {
   
//Modify by pega Huimin 2009.12.18 to support HW USB power control design
#if (DEVICE_USB_HW_DESIGN)
	//OTG_EN = 1
	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D16), 1);
	printk("%s:%d\n",__FUNCTION__,on);
	mdelay(10);
#endif

      //----------------
      // close VBUS
      //----------------
      // REG_SW_5 = REG_29[20] = SWBSTEN = 0
      pmic_read_reg(REG_SW_5, &value, 0xFFFFFF);
      value &= ~0x100000;
      pmic_write_reg(REG_SW_5, value, 0xFFFFFF);

      // REG_USB1 = REG_50[0] = VUSBIN = 0 , REG_50[10] = OTGSWBSTEN = 0
      pmic_read_reg(REG_USB1, &value, 0xFFFFFF);
      value &= ~0x000401;
      pmic_write_reg(REG_USB1, value, 0xFFFFFF);
      mdelay(10);

      //----------------
      // open charging
      //----------------
      pmic_battery_start_charge ();
   }
}
EXPORT_SYMBOL(usb_vbus_power);

//---------------------------------
// add by pega Kevin 2009.11.10
//---------------------------------
// debug for drivers/usb/fsl_otg.c
//---------------------------------
unsigned int pmic_debug_read(int reg)
{
   unsigned int value;

   pmic_read_reg(reg, &value, 0xFFFFFF);
   return value;
}
EXPORT_SYMBOL(pmic_debug_read);
//---------------------------------
// end modify - USB OTG VBUS power change
//--------------------------------
