rk31xx:RT5025:support pmic rt5025
author张晴 <zhangqing@rock-chips.com>
Thu, 4 Jul 2013 07:09:13 +0000 (15:09 +0800)
committer张晴 <zhangqing@rock-chips.com>
Thu, 4 Jul 2013 07:09:13 +0000 (15:09 +0800)
27 files changed:
arch/arm/mach-rk30/board-pmu-rt5025.c [new file with mode: 0755]
arch/arm/mach-rk30/board-rk3168-tb.c
arch/arm/plat-rk/include/plat/board.h
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/rt5025-gpio.c [new file with mode: 0755]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/rt5025-core.c [new file with mode: 0755]
drivers/mfd/rt5025-debug.c [new file with mode: 0755]
drivers/mfd/rt5025-i2c.c [new file with mode: 0755]
drivers/mfd/rt5025-irq.c [new file with mode: 0755]
drivers/mfd/rt5025-misc.c [new file with mode: 0755]
drivers/power/Kconfig [changed mode: 0644->0755]
drivers/power/Makefile [changed mode: 0644->0755]
drivers/power/rt5025-gauge.c [new file with mode: 0755]
drivers/power/rt5025-power.c [new file with mode: 0755]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/rt5025-regulator.c [new file with mode: 0755]
include/linux/mfd/rt5025-gpio.h [new file with mode: 0755]
include/linux/mfd/rt5025-irq.h [new file with mode: 0755]
include/linux/mfd/rt5025-misc.h [new file with mode: 0755]
include/linux/mfd/rt5025.h [new file with mode: 0755]
include/linux/power/rt5025-gauge.h [new file with mode: 0755]
include/linux/power/rt5025-power.h [new file with mode: 0755]
include/linux/regulator/rt5025-regulator.h [new file with mode: 0755]

diff --git a/arch/arm/mach-rk30/board-pmu-rt5025.c b/arch/arm/mach-rk30/board-pmu-rt5025.c
new file mode 100755 (executable)
index 0000000..7b48c7b
--- /dev/null
@@ -0,0 +1,458 @@
+#include <linux/regulator/machine.h>
+#include <mach/sram.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+
+#include <linux/mfd/rt5025.h>
+
+#ifdef CONFIG_MFD_RT5025
+
+static int rt5025_pre_init(struct rt5025_chip *rt5025_chip){
+
+       
+       printk("%s,line=%d\n", __func__,__LINE__);      
+       int ret;
+       /**********set voltage speed***********************/
+       ret = rt5025_reg_read(rt5025_chip->i2c, 0x08);
+       ret &= (~(3<<0));  //dcdc1 25mv/10us
+       rt5025_reg_write(rt5025_chip->i2c, 0x08,ret);
+       
+       ret = rt5025_reg_read(rt5025_chip->i2c, 0x09);
+       ret &= (~(3<<0));//dcdc2 100mv/10us
+       rt5025_reg_write(rt5025_chip->i2c, 0x09,ret);
+       
+       ret = rt5025_reg_read(rt5025_chip->i2c, 0x0a);
+       ret &= (~(3<<0));//dcdc3 50mv/12us
+       rt5025_reg_write(rt5025_chip->i2c, 0x0a,ret);
+       /************************************************/
+       /***************set power off voltage***************/
+       ret = rt5025_reg_read(rt5025_chip->i2c, 0x17);
+       ret &= (~(7<<5));  //power off 2.8v
+       rt5025_reg_write(rt5025_chip->i2c, 0x17,ret);
+
+       ret = rt5025_reg_read(rt5025_chip->i2c, 0x17);
+       ret |= (1<<3);  //enable DC4 boost
+       rt5025_reg_write(rt5025_chip->i2c, 0x17,ret);
+       /***********************************************/
+       /************************************************/
+       return 0;
+  }
+static int rt5025_post_init(void)
+{
+       struct regulator *dcdc;
+       struct regulator *ldo;
+       int i = 0;
+       printk("%s,line=%d\n", __func__,__LINE__);
+
+       #ifndef CONFIG_RK_CONFIG
+       g_pmic_type = PMIC_TYPE_RT5025;
+       #endif
+       printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type);
+       
+       for(i = 0; i < ARRAY_SIZE(rt5025_dcdc_info); i++)
+       {
+                if(rt5025_dcdc_info[i].min_uv == 0 && rt5025_dcdc_info[i].max_uv == 0)
+                        continue;
+               dcdc =regulator_get(NULL, rt5025_dcdc_info[i].name);
+
+               regulator_set_voltage(dcdc, rt5025_dcdc_info[i].min_uv, rt5025_dcdc_info[i].max_uv);
+
+               regulator_set_mode(dcdc, REGULATOR_MODE_NORMAL);
+               regulator_enable(dcdc);
+               printk("%s  %s =%duV end\n", __func__,rt5025_dcdc_info[i].name, regulator_get_voltage(dcdc));
+               regulator_put(dcdc);
+               udelay(100);
+       }
+       
+       for(i = 0; i < ARRAY_SIZE(rt5025_ldo_info); i++)
+       {
+                if(rt5025_ldo_info[i].min_uv == 0 && rt5025_ldo_info[i].max_uv == 0)
+                        continue;
+               ldo =regulator_get(NULL, rt5025_ldo_info[i].name);
+               regulator_set_voltage(ldo, rt5025_ldo_info[i].min_uv, rt5025_ldo_info[i].max_uv);
+               regulator_enable(ldo);
+               printk("%s  %s =%duV end\n", __func__,rt5025_ldo_info[i].name, regulator_get_voltage(ldo));
+               regulator_put(ldo);
+       }
+       
+       printk("%s,line=%d END\n", __func__,__LINE__);
+       
+       return 0;
+}
+static struct regulator_consumer_supply rt5025_dcdc1_supply[] = {
+       {
+               .supply = "rt5025-dcdc1",
+       },
+//     {
+//             .supply = "vdd_cpu",
+//     },
+       
+};
+static struct regulator_consumer_supply rt5025_dcdc2_supply[] = {
+       {
+               .supply = "rt5025-dcdc2",
+       },
+//     {
+//             .supply = "vdd_core",
+//     },
+};
+static struct regulator_consumer_supply rt5025_dcdc3_supply[] = {
+       {
+               .supply = "rt5025-dcdc3",
+       },
+};
+
+static struct regulator_consumer_supply rt5025_dcdc4_supply[] = {
+       {
+               .supply = "rt5025-dcdc4",
+       },
+};
+
+static struct regulator_consumer_supply rt5025_ldo1_supply[] = {
+       {
+               .supply = "rt5025-ldo1",
+       },
+};
+static struct regulator_consumer_supply rt5025_ldo2_supply[] = {
+       {
+               .supply = "rt5025-ldo2",
+       },
+};
+
+static struct regulator_consumer_supply rt5025_ldo3_supply[] = {
+       {
+               .supply = "rt5025-ldo3",
+       },
+};
+static struct regulator_consumer_supply rt5025_ldo4_supply[] = {
+       {
+               .supply = "rt5025-ldo4",
+       },
+};
+static struct regulator_consumer_supply rt5025_ldo5_supply[] = {
+       {
+               .supply = "rt5025-ldo5",
+       },
+};
+static struct regulator_consumer_supply rt5025_ldo6_supply[] = {
+       {
+               .supply = "rt5025-ldo6",
+       },
+};
+
+static struct regulator_init_data rt5025_dcdc1_info = {
+       .constraints = {
+               .name           = "RT5025-DCDC1",
+               .min_uV =  700000,
+               .max_uV = 2275000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS| REGULATOR_CHANGE_MODE,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc1_supply),
+       .consumer_supplies =  rt5025_dcdc1_supply,
+};
+
+static struct regulator_init_data rt5025_dcdc2_info = {
+       .constraints = {
+               .name           = "RT5025-DCDC2",
+               .min_uV =  700000,
+               .max_uV = 3500000,
+               .valid_modes_mask =  REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS  | REGULATOR_CHANGE_MODE,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc2_supply),
+       .consumer_supplies =  rt5025_dcdc2_supply,
+};
+
+static struct regulator_init_data rt5025_dcdc3_info = {
+       .constraints = {
+               .name           = "RT5025-DCDC3",
+               .min_uV =  700000,
+               .max_uV = 3500000,
+               .valid_modes_mask =  REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS  | REGULATOR_CHANGE_MODE,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc3_supply),
+       .consumer_supplies =  rt5025_dcdc3_supply,
+};
+
+static struct regulator_init_data rt5025_dcdc4_info = {
+       .constraints = {
+               .name           = "RT5025-DCDC4",
+               .min_uV = 4500000,
+               .max_uV = 5500000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc4_supply),
+       .consumer_supplies =  rt5025_dcdc4_supply,
+};
+
+static struct regulator_init_data rt5025_ldo1_info = {
+       .constraints = {
+               .name           = "RT5025-LDO1",
+               .min_uV =  700000,
+               .max_uV = 3500000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo1_supply),
+       .consumer_supplies =  rt5025_ldo1_supply,
+};
+
+static struct regulator_init_data rt5025_ldo2_info = {
+       .constraints = {
+               .name           = "RT5025-LDO2",
+               .min_uV =  700000,
+               .max_uV = 3500000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo2_supply),
+       .consumer_supplies =  rt5025_ldo2_supply,
+};
+
+static struct regulator_init_data rt5025_ldo3_info = {
+       .constraints = {
+               .name           = "RT5025-LDO3",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo3_supply),
+       .consumer_supplies =  rt5025_ldo3_supply,
+};
+
+static struct regulator_init_data rt5025_ldo4_info = {
+       .constraints = {
+               .name           = "RT5025-LDO4",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo4_supply),
+       .consumer_supplies =  rt5025_ldo4_supply,
+};
+
+static struct regulator_init_data rt5025_ldo5_info = {
+       .constraints = {
+               .name           = "RT5025-LDO5",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo5_supply),
+       .consumer_supplies =  rt5025_ldo5_supply,
+};
+
+static struct regulator_init_data rt5025_ldo6_info = {
+       .constraints = {
+               .name           = "RT5025-LDO6",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo6_supply),
+       .consumer_supplies =  rt5025_ldo6_supply,
+};
+
+static struct rt5025_power_data rt5025_power_data = {
+       .CHGControl2 = {
+               .bitfield = {
+                       .CHGBC_EN = 1,
+                       .TE = 1,
+                       .CCCHG_TIMEOUT = RT5025_CCCHG_TO_6H,
+                       .PRECHG_TIMEOUT = RT5025_PRECHG_TO_30M,
+               },
+       },
+       .CHGControl3 = {
+               .bitfield = {
+                       .VOREG = 0x23,
+               },
+       },
+       .CHGControl4 = {
+               .bitfield = {
+                       .AICR = RT5025_AICR_500MA,
+                       .ICC = RT5025_ICC_1P8A,
+               },
+       },
+       .CHGControl5 = {
+               .bitfield = {
+                       .DPM = RT5025_DPM_DIS,
+               },
+       },
+       .CHGControl6 = {
+               .bitfield = {
+                       .IPREC = RT5025_IPREC_10P,
+                       .IEOC = RT5025_IEOC_10P,
+                       .VPREC = RT5025_VPREC_3V,
+               },
+       },
+       .CHGControl7 = {
+               .bitfield = {
+                       .CHGC_EN = 1,
+                       .CHG_DCDC_MODE = 0,
+                       .BATD_EN = 0,
+               },
+       },
+};
+
+static struct rt5025_gpio_data rt5025_gpio_data = {
+//     .gpio_base = RT5025_GPIO_BASE,
+       .irq_base = IRQ_BOARD_BASE,
+};
+
+static struct rt5025_misc_data rt5025_misc_data = {
+       .RSTCtrl = {
+               .bitfield = {
+                       .Action = 2,
+                       .Delayed1 = RT5025_RSTDELAY1_1S,
+                       .Delayed2 = RT5025_RSTDELAY2_1S,
+               },
+       },
+       .VSYSCtrl = {
+               .bitfield = {
+                       .VOFF = RT5025_VOFF_3P1V,
+               },
+       },
+       .PwrOnCfg = {
+               .bitfield = {
+                       .PG_DLY = RT5025_PGDLY_100MS,
+                       .SHDN_PRESS = RT5025_SHDNPRESS_6S,
+                       .LPRESS_TIME = RT5025_LPRESS_1P5S,
+                       .START_TIME = RT5025_STARTIME_100MS,
+               },
+       },
+       .SHDNCtrl = {
+               .bitfield = {
+                       .SHDN_DLYTIME = RT5025_SHDNDLY_1S,
+                       .SHDN_TIMING = 1,
+                       .SHDN_CTRL = 0,
+               },
+       },
+       .PwrOffCond = {
+               .bitfield = {
+                       .OT_ENSHDN = 1,
+                       .PWRON_ENSHDN = 1,
+                       .DCDC3LV_ENSHDN = 0,
+                       .DCDC2LV_ENSHDN = 0,
+                       .DCDC1LV_ENSHDN = 0,
+                       .SYSLV_ENSHDN = 0,
+               },
+       },
+};
+
+static struct rt5025_irq_data rt5025_irq_data = {
+       .irq_enable1 = {
+               .bitfield = {
+                       .BATABS = 1,
+                       .INUSB_PLUGIN = 1,
+                       .INUSBOVP = 1,
+                       .INAC_PLUGIN = 1,
+                       .INACOVP = 1,
+               },
+       },
+       .irq_enable2 = {
+               .bitfield = {
+                       .CHTERMI = 1,
+                       .CHBATOVI = 1,
+                       .CHGOODI_INUSB = 0,
+                       .CHBADI_INUSB = 1,
+                       .CHSLPI_INUSB = 1,
+                       .CHGOODI_INAC = 0,
+                       .CHBADI_INAC = 1,
+                       .CHSLPI_INAC = 1,
+               },
+       },
+       .irq_enable3 = {
+               .bitfield = {
+                       .TIMEOUT_CC = 1,
+                       .TIMEOUT_PC = 1,
+                       .CHVSREGI = 0,
+                       .CHTREGI = 0,
+                       .CHRCHGI = 0,
+               },
+       },
+       .irq_enable4 = {
+               .bitfield = {
+                       .SYSLV = 0,
+                       .DCDC4LVHV = 1,
+                       .PWRONLP = 0,
+                       .PWRONSP = 0,
+                       .DCDC3LV = 1,
+                       .DCDC2LV = 1,
+                       .DCDC1LV = 1,
+                       .OT = 1,
+               },
+       },
+       .irq_enable5 = {
+               .bitfield = {
+                       .GPIO0_IE = 0,
+                       .GPIO1_IE = 0,
+                       .GPIO2_IE = 0,
+                       .RESETB = 1,
+                       .PWRONF = 0,
+                       .PWRONR = 0,
+                       .KPSHDN = 1,
+               },
+       },
+};
+
+static void rt5025_charger_event_callback(uint32_t detected)
+{
+       RTINFO("event detected = 0x%08x\n", detected);
+}
+
+static void rt5025_power_event_callback(uint32_t detected)
+{
+       RTINFO("event detected = 0x%08x\n", detected);
+}
+
+static struct rt5025_event_callback rt5025_event_callback = {
+       .charger_event_callback = rt5025_charger_event_callback,
+       .power_event_callkback = rt5025_power_event_callback,
+};
+
+static struct rt5025_platform_data rt5025_data = {
+       .pre_init=rt5025_pre_init,
+       .post_init=rt5025_post_init,
+       .regulator = {
+               &rt5025_dcdc1_info,
+               &rt5025_dcdc2_info,
+               &rt5025_dcdc3_info,
+               &rt5025_dcdc4_info,
+               &rt5025_ldo1_info,
+               &rt5025_ldo2_info,
+               &rt5025_ldo3_info,
+               &rt5025_ldo4_info,
+               &rt5025_ldo5_info,
+               &rt5025_ldo6_info,
+       },
+       .power_data = &rt5025_power_data,
+       .gpio_data = &rt5025_gpio_data,
+       .misc_data = &rt5025_misc_data,
+       .irq_data = &rt5025_irq_data,
+       .cb = &rt5025_event_callback,
+       .intr_pin = 81, //GPIO81
+};
+
+void __sramfunc board_pmu_rt5025_suspend(void)
+{      
+}
+void __sramfunc board_pmu_rt5025_resume(void)
+{
+}
+
+
+#endif
+
+
+
+
index 592af755211ed714cfc45309c615c6f60580436b..677aefa727f8f7658e8a2339ab297f69fbb0bf53 100755 (executable)
@@ -49,6 +49,9 @@
 #include <linux/mfd/rk808.h>
 #include <linux/mfd/ricoh619.h>
 #include <linux/regulator/rk29-pwm-regulator.h>
+#ifdef CONFIG_MFD_RT5025
+#include <linux/mfd/rt5025.h>
+#endif
 
 #ifdef CONFIG_CW2015_BATTERY
 #include <linux/power/cw2015_battery.h>
@@ -2079,6 +2082,65 @@ static  struct pmu_info  ricoh619_ldo_info[] = {
 #include "board-pmu-ricoh619.c"
 #endif
 
+#ifdef CONFIG_MFD_RT5025
+#define RT5025_HOST_IRQ        RK30_PIN0_PB3
+
+static struct pmu_info  rt5025_dcdc_info[] = {
+       {
+               .name          = "rt5025-dcdc1",   //arm
+               .min_uv          = 1000000,
+               .max_uv         = 1000000,
+       },
+       {
+               .name          = "rt5025-dcdc2",    //logic
+               .min_uv          = 1000000,
+               .max_uv         = 1000000,
+       },
+       
+       {
+               .name          = "rt5025-dcdc3",   //vccio
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+       },
+       
+};
+static  struct pmu_info  rt5025_ldo_info[] = {
+       {
+               .name          = "rt5025-ldo1",   //vdd10
+               .min_uv          = 1000000,
+               .max_uv         = 1000000,
+       },
+       {
+               .name          = "rt5025-ldo2",    //vddjetta
+               .min_uv          = 1200000,
+               .max_uv         = 1200000,
+       },
+       {
+               .name          = "rt5025-ldo3",   //vcc18
+               .min_uv          = 1800000,
+               .max_uv         = 1800000,
+       },
+       {
+               .name          = "rt5025-ldo4",   //vccjetta
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+       },
+       {
+               .name          = "rt5025-ldo5",   //vcctp
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+       },
+       {
+               .name          = "rt5025-ldo6",   //vccio_wl
+               .min_uv          = 1800000,
+               .max_uv         = 1800000,
+       },      
+       
+ };
+
+#include "board-pmu-rt5025.c"
+#endif
+
 
 
 static struct i2c_board_info __initdata i2c1_info[] = {
@@ -2130,6 +2192,16 @@ static struct i2c_board_info __initdata i2c1_info[] = {
        },
 #endif
 
+#if defined (CONFIG_MFD_RT5025)
+       {
+               .type                   = "RT5025",
+               .addr           = 0x35,
+               .flags                  = 0,
+              .irq            = RT5025_HOST_IRQ,
+              .platform_data=&rt5025_data,
+       },
+#endif
+
 #if defined (CONFIG_RTC_HYM8563)
        {
                .type                   = "rtc_hym8563",
@@ -2438,6 +2510,12 @@ static void rk30_pm_power_off(void)
        }
        #endif
 
+       #if defined(CONFIG_MFD_RT5025) 
+       if(pmic_is_rt5025()){
+       rt5025_power_off();    //rt5025 shutdown
+       }
+       #endif
+
        gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
        while (1);
 }
index 9d14b1e56a578b411c4a914a74df6afa12f41255..45bd521e5de91640c853382dc764135fa6f2796f 100755 (executable)
@@ -91,6 +91,7 @@ enum {
        PMIC_TYPE_ACT8846 =3,
        PMIC_TYPE_RK808 =4,
        PMIC_TYPE_RICOH619 =5,
+       PMIC_TYPE_RT5025 =6,
        PMIC_TYPE_MAX,
 };
 extern __sramdata  int g_pmic_type;
@@ -100,6 +101,7 @@ extern __sramdata  int g_pmic_type;
 #define pmic_is_act8846()  (g_pmic_type == PMIC_TYPE_ACT8846)
 #define pmic_is_rk808()  (g_pmic_type == PMIC_TYPE_RK808)
 #define pmic_is_ricoh619()  (g_pmic_type == PMIC_TYPE_RICOH619)
+#define pmic_is_rt5025()  (g_pmic_type == PMIC_TYPE_RT5025)
 
 struct  pmu_info {
        char            *name;
index fbdbde2b3efabbf37c67f9001aad60cfbd12bee0..dadd65efd04e83673a1ae84ce603d6e0129b8315 100755 (executable)
@@ -499,4 +499,10 @@ config GPIO_TPS65910
        help
          Select this option to enable GPIO driver for the TPS65910
          chip family.
+config GPIO_RT5025
+       bool "Richtek RT5025 GPIO support"
+       depends on MFD_RT5025
+       default n
+       help
+         This is the gpio driver for RT5025 PMIC.
 endif
index 54e59b9e093909ba4c473bbcc389abfc3019a216..55451aa37a54ca28d3458b191843030a13da9485 100755 (executable)
@@ -56,3 +56,4 @@ obj-$(CONFIG_GPIO_ML_IOH)     += ml_ioh_gpio.o
 obj-$(CONFIG_AB8500_GPIO)       += ab8500-gpio.o
 obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
 obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
+obj-$(CONFIG_GPIO_RT5025)      += rt5025-gpio.o
diff --git a/drivers/gpio/rt5025-gpio.c b/drivers/gpio/rt5025-gpio.c
new file mode 100755 (executable)
index 0000000..e4636f9
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *  drivers/gpio/rt5025-gpio.c
+ *  Driver foo Richtek RT5025 PMIC GPIO
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-gpio.h>
+
+struct rt5025_gpio_info {
+       struct i2c_client *i2c;
+       unsigned gpio_base;
+       unsigned irq_base;
+       struct gpio_chip gpio_chip;
+};
+
+static inline int find_rt5025_gpioreg(unsigned off, int *gpio_reg)
+{
+       int ret = 0;
+       switch (off)
+       {
+               case 0:
+               case 1:
+               case 2:
+                       *gpio_reg = RT5025_REG_GPIO0 + off;
+                       break;
+               default:
+                       ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int rt5025_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+       int gpio_reg = 0;
+       int ret = 0;
+       
+       ret = find_rt5025_gpioreg(offset , &gpio_reg);
+       if (ret < 0)
+       {
+               dev_err(chip->dev, "not a valid gpio index\n");
+               return ret;
+       }
+
+       ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRMASK);
+       if (ret<0)
+       {
+               dev_err(chip->dev, "set gpio input fail\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rt5025_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+       int gpio_reg = 0;
+       int ret = 0;
+       
+       ret = find_rt5025_gpioreg(offset, &gpio_reg);
+       if (ret < 0)
+       {
+               dev_err(chip->dev, "not a valid gpio index\n");
+               return ret;
+       }
+       
+       ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRSHIFT);
+       if (ret<0)
+       {
+               dev_err(chip->dev, "clr gpio direction fail\n");
+               return ret;
+       }
+
+       ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OUTPUT<<RT5025_GPIO_DIRSHIFT);
+       if (ret<0)
+       {
+               dev_err(chip->dev, "set gpio output dir fail\n");
+               return ret;
+       }
+
+       if (value)
+               ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+       else
+               ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+
+       if (ret<0)
+       {
+               dev_err(chip->dev, "set gpio output value fail\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rt5025_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+       int gpio_reg = 0;
+       int ret = 0;
+       
+       ret = find_rt5025_gpioreg(offset, &gpio_reg);
+       if (ret < 0)
+       {
+               dev_err(chip->dev, "not a valid gpio index\n");
+               return ret;
+       }
+       
+       ret = rt5025_reg_read(gi->i2c, gpio_reg);
+       if (ret<0)
+       {
+               dev_err(chip->dev, "read gpio register fail\n");
+               return ret;
+       }
+
+       return (ret&RT5025_GPIO_IVALUEMASK)?1:0;
+}
+
+static void rt5025_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+       int gpio_reg = 0;
+       int ret = 0;
+       
+       ret = find_rt5025_gpioreg(offset, &gpio_reg);
+       if (ret < 0)
+       {
+               dev_err(chip->dev, "not a valid gpio index\n");
+               return;
+       }
+
+       if (value)
+               ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+       else
+               ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+
+       if (ret<0)
+       {
+               dev_err(chip->dev, "read gpio register fail\n");
+       }
+}
+
+static int __devinit rt5025_gpio_probe(struct platform_device *pdev)
+{
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5025_platform_data *pdata = chip->dev->platform_data;
+       struct rt5025_gpio_info *gi;
+       int ret = 0;
+
+       gi = kzalloc(sizeof(*gi), GFP_KERNEL);
+       if (!gi)
+               return -ENOMEM;
+
+       gi->i2c = chip->i2c;
+       gi->gpio_base = pdata->gpio_data->gpio_base;
+       gi->irq_base = pdata->gpio_data->irq_base;
+
+       gi->gpio_chip.direction_input  = rt5025_gpio_direction_input;
+       gi->gpio_chip.direction_output = rt5025_gpio_direction_output;
+       gi->gpio_chip.get = rt5025_gpio_get_value;
+       gi->gpio_chip.set = rt5025_gpio_set_value;
+       gi->gpio_chip.can_sleep = 0;
+
+       gi->gpio_chip.base = gi->gpio_base;
+       gi->gpio_chip.ngpio = RT5025_GPIO_NR;
+       gi->gpio_chip.label = pdev->name;
+       gi->gpio_chip.dev = &pdev->dev;
+       gi->gpio_chip.owner = THIS_MODULE;
+
+       ret = gpiochip_add(&gi->gpio_chip);
+       if (ret)
+               goto out_dev;
+               
+       platform_set_drvdata(pdev, gi);
+       return ret;
+out_dev:
+       kfree(gi);
+       return ret;
+}
+
+static int __devexit rt5025_gpio_remove(struct platform_device *pdev)
+{
+       int ret;
+       struct rt5025_gpio_info *gi = platform_get_drvdata(pdev);
+
+       ret = gpiochip_remove(&gi->gpio_chip);
+       kfree(gi);
+
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver rt5025_gpio_driver = 
+{
+       .driver = {
+               .name = RT5025_DEVICE_NAME "-gpio",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5025_gpio_probe,
+       .remove = __devexit_p(rt5025_gpio_remove),
+};
+
+static int __init rt5025_gpio_init(void)
+{
+       return platform_driver_register(&rt5025_gpio_driver);
+}
+subsys_initcall_sync(rt5025_gpio_init);
+
+static void __exit rt5025_gpio_exit(void)
+{
+       platform_driver_unregister(&rt5025_gpio_driver);
+}
+module_exit(rt5025_gpio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("GPIO driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-gpio");
index 1ad97adbcdb0677117b90b243070a4f42fd8e292..2628e73d0e653353347ac965b0ac3d121c97c124 100644 (file)
@@ -835,6 +835,36 @@ config MFD_TPS65090
          This driver provides common support for accessing the device,
          additional drivers must be enabled in order to use the
          functionality of the device.
+         
+config MFD_RT5025
+       bool "RT5025 PMIC Chip Core driver"
+       depends on I2C
+       select MFD_CORE
+       default n
+       help
+         Enable RT5025 core driver.
+
+config MFD_RT5025_MISC
+       bool "RT5025 PMIC chip misc configuration"
+       depends on MFD_RT5025
+       default n
+       help
+         Enable RT5025 Misc configuration.
+
+config MFD_RT5025_IRQ
+       bool "RT5025_PMIC chip irq driver"
+       depends on MFD_RT5025
+       default n
+       help
+         Enable RT5025 IRQ configuration and interrupt.
+
+config MFD_RT5025_DEBUG
+       bool "RT5025 PMIC Chip Core Debug"
+       depends on MFD_RT5025 && DEBUG_FS
+       default n
+       help
+         Enable RT5025 core debug driver.
+
 
 config MFD_RK610
        bool "RK610(Jetta) Multimedia support"
index 6679b0b46f68caffe5d976e764025a283dbcedc0..02f319a24493bcae5ea03055a936c66b4cefe6d7 100644 (file)
@@ -111,3 +111,7 @@ obj-$(CONFIG_MFD_RK610)     += rk610-core.o
 obj-$(CONFIG_MFD_RK808)        += rk808.o rk808-irq.o
 obj-$(CONFIG_MFD_RK616) += rk616-core.o rk616-vif.o
 obj-$(CONFIG_MFD_RICOH619)     += ricoh619.o ricoh619-irq.o
+obj-$(CONFIG_MFD_RT5025)       += rt5025-i2c.o rt5025-core.o
+obj-$(CONFIG_MFD_RT5025_MISC)  += rt5025-misc.o
+obj-$(CONFIG_MFD_RT5025_IRQ)   += rt5025-irq.o
+obj-$(CONFIG_MFD_RT5025_DEBUG) += rt5025-debug.o
diff --git a/drivers/mfd/rt5025-core.c b/drivers/mfd/rt5025-core.c
new file mode 100755 (executable)
index 0000000..51e59e1
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *  drivers/mfd/rt5025-core.c
+ *  Driver for Richtek RT5025 Core PMIC
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+
+#include <linux/mfd/rt5025.h>
+
+#ifdef CONFIG_REGULATOR_RT5025
+#define RT5025_VR_DEVS(_id)                                            \
+{                                                                      \
+       .name           = RT5025_DEVICE_NAME "-regulator",                              \
+       .num_resources  = 0,                                            \
+       .id             = RT5025_ID_##_id,                              \
+}
+
+static struct mfd_cell regulator_devs[] = {
+       RT5025_VR_DEVS(DCDC1),
+       RT5025_VR_DEVS(DCDC2),
+       RT5025_VR_DEVS(DCDC3),
+       RT5025_VR_DEVS(DCDC4),
+       RT5025_VR_DEVS(LDO1),
+       RT5025_VR_DEVS(LDO2),
+       RT5025_VR_DEVS(LDO3),
+       RT5025_VR_DEVS(LDO4),
+       RT5025_VR_DEVS(LDO5),
+       RT5025_VR_DEVS(LDO6),
+};
+#endif /* CONFIG_REGULATOR_RT5025 */
+
+#ifdef CONFIG_POWER_RT5025
+static struct mfd_cell power_devs[] = {
+{
+       .name = RT5025_DEVICE_NAME "-power",
+       .id = -1,
+       .num_resources = 0,
+},
+};
+#endif /* CONFIG_POWER_RT5025 */
+
+#ifdef CONFIG_GPIO_RT5025
+static struct mfd_cell gpio_devs[] = {
+{
+       .name = RT5025_DEVICE_NAME "-gpio",
+       .id = -1,
+       .num_resources = 0,
+},
+};
+#endif /* CONFIG_GPIO_RT5025 */
+
+#ifdef CONFIG_MFD_RT5025_MISC
+static struct mfd_cell misc_devs[] = {
+{
+       .name = RT5025_DEVICE_NAME "-misc",
+       .id = -1,
+       .num_resources = 0,
+},
+};
+#endif /* CONFIG_MFD_RT5025_MISC */
+
+#ifdef CONFIG_MFD_RT5025_IRQ
+static struct mfd_cell irq_devs[] = {
+{
+       .name = RT5025_DEVICE_NAME "-irq",
+       .id = -1,
+       .num_resources = 0,
+},
+};
+#endif /* CONFIG_MFD_RT5025_IRQ */
+
+#ifdef CONFIG_MFD_RT5025_DEBUG
+static struct mfd_cell debug_devs[] = {
+{
+       .name = RT5025_DEVICE_NAME "-debug",
+       .id = -1,
+       .num_resources = 0,
+},
+};
+#endif /* CONFIG_MFD_RT5025_DEBUG */
+
+int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_data *pdata)
+{
+       int ret = 0;
+
+       RTINFO("Start to initialize all device\n");
+       printk("%s,line=%d\n", __func__,__LINE__);
+
+       #ifdef CONFIG_REGULATOR_RT5025
+       if (pdata && pdata->regulator[0]) {
+               RTINFO("mfd add regulators dev\n");
+               #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+               ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+                                     ARRAY_SIZE(regulator_devs),
+                                     NULL, 0, NULL);
+               #else
+               ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+                                     ARRAY_SIZE(regulator_devs),
+                                     NULL, 0);
+               #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(chip->dev, "Failed to add regulator subdev\n");
+                       goto out_dev;
+               }
+       }
+       #endif /* CONFIG_REGULATOR_RT5025 */
+
+       #ifdef CONFIG_POWER_RT5025
+       if (pdata && pdata->power_data) {
+           RTINFO("mfd add power dev\n");
+               #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+               ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+                                       ARRAY_SIZE(power_devs),
+                                       NULL, 0,NULL);
+               #else
+               ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+                                       ARRAY_SIZE(power_devs),
+                                       NULL, 0);
+               #endif
+               if (ret < 0) {
+                       dev_err(chip->dev, "Failed to add power supply "
+                               "subdev\n");
+                       goto out_dev;
+               }
+       }
+       #endif /* CONFIG_MFD_RT5025 */
+
+       //Initialize the RT5025_GPIO
+       #ifdef CONFIG_GPIO_RT5025
+       if (pdata && pdata->gpio_data) {
+               RTINFO("mfd add gpios dev\n");
+               #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+               ret = mfd_add_devices(chip->dev, 0, &gpio_devs[0],
+                                     ARRAY_SIZE(gpio_devs),
+                                     NULL, 0, NULL);
+               #else
+               ret = mfd_add_devices(chip->dev, 0, &gpio_devs[0],
+                                     ARRAY_SIZE(gpio_devs),
+                                     NULL, 0);
+               #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(chip->dev, "Failed to add gpio subdev\n");
+                       goto out_dev;
+               }
+       }
+       #endif /* CONFIG_GPIO_RT5025 */
+\
+       #ifdef CONFIG_MFD_RT5025_MISC
+       if (pdata && pdata->misc_data) {
+               RTINFO("mfd add misc dev\n");
+               #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+               ret = mfd_add_devices(chip->dev, 0, &misc_devs[0],
+                                     ARRAY_SIZE(misc_devs),
+                                     NULL, 0, NULL);
+               #else
+               ret = mfd_add_devices(chip->dev, 0, &misc_devs[0],
+                                     ARRAY_SIZE(misc_devs),
+                                     NULL, 0);
+               #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(chip->dev, "Failed to add misc subdev\n");
+                       goto out_dev;
+               }
+       }
+       #endif /* CONFIG_MFD_RT5025_MISC */
+
+       #ifdef CONFIG_MFD_RT5025_IRQ
+       if (pdata && pdata->irq_data) {
+               RTINFO("mfd add irq dev\n");
+               #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+               ret = mfd_add_devices(chip->dev, 0, &irq_devs[0],
+                                     ARRAY_SIZE(irq_devs),
+                                     NULL, 0, NULL);
+               #else
+               ret = mfd_add_devices(chip->dev, 0, &irq_devs[0],
+                                     ARRAY_SIZE(irq_devs),
+                                     NULL, 0);
+               #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(chip->dev, "Failed to add irq subdev\n");
+                       goto out_dev;
+               }
+       }
+       #endif /* CONFIG_MFD_RT5025_IRQ */
+#if 0
+       #ifdef CONFIG_MFD_RT5025_DEBUG
+       RTINFO("mfd add debug dev\n");
+       printk("%s,line=%d\n", __func__,__LINE__);
+       #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+       ret = mfd_add_devices(chip->dev, 0, &debug_devs[0],
+                             ARRAY_SIZE(debug_devs),
+                             NULL, 0, NULL);
+       #else
+       ret = mfd_add_devices(chip->dev, 0, &debug_devs[0],
+                             ARRAY_SIZE(debug_devs),
+                             NULL, 0);
+       #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to add debug subdev\n");
+               goto out_dev;
+       }
+       #endif /* CONFIG_MFD_RT5025_DEBUG */
+#endif
+       
+       RTINFO("Initialize all device successfully\n");
+       return ret;
+out_dev:
+       mfd_remove_devices(chip->dev);
+       return ret;
+}
+subsys_initcall_sync(rt5025_core_init);
+
+int __devexit rt5025_core_deinit(struct rt5025_chip *chip)
+{
+       mfd_remove_devices(chip->dev);
+       return 0;
+}
+EXPORT_SYMBOL(rt5025_core_deinit);
diff --git a/drivers/mfd/rt5025-debug.c b/drivers/mfd/rt5025-debug.c
new file mode 100755 (executable)
index 0000000..bec09d6
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *  drivers/mfd/rt5025-debug.c
+ *  Driver foo Richtek RT5025 PMIC Debug
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/string.h>
+
+#include <linux/mfd/rt5025.h>
+
+struct rt5025_debug_info {
+       struct i2c_client *i2c;
+};
+
+static struct i2c_client *client;
+static struct dentry *debugfs_rt_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+
+static unsigned char read_data;
+
+static int reg_debug_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+       char *token;
+       int base, cnt;
+
+       token = strsep(&buf, " ");
+
+       for (cnt = 0; cnt < num_of_par; cnt++) {
+               if (token != NULL) {
+                       if ((token[1] == 'x') || (token[1] == 'X'))
+                               base = 16;
+                       else
+                               base = 10;
+
+                       if (strict_strtoul(token, base, &param1[cnt]) != 0)
+                               return -EINVAL;
+
+                       token = strsep(&buf, " ");
+                       }
+               else
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static ssize_t reg_debug_read(struct file *filp, char __user *ubuf,
+                               size_t count, loff_t *ppos)
+{
+       char lbuf[8];
+       
+       snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
+       return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf));
+}
+
+static ssize_t reg_debug_write(struct file *filp,
+       const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+       char *access_str = filp->private_data;
+       char lbuf[32];
+       int rc;
+       long int param[5];
+
+       if (cnt > sizeof(lbuf) - 1)
+               return -EINVAL;
+
+       rc = copy_from_user(lbuf, ubuf, cnt);
+       if (rc)
+               return -EFAULT;
+
+       lbuf[cnt] = '\0';
+
+       if (!strcmp(access_str, "poke")) {
+               /* write */
+               rc = get_parameters(lbuf, param, 2);
+               if ((param[0] <= 0xFF) && (param[1] <= 0xFF) && (rc == 0))
+               {
+                       rt5025_reg_write(client, param[0], (unsigned char)param[1]);
+               }
+               else
+                       rc = -EINVAL;
+       } else if (!strcmp(access_str, "peek")) {
+               /* read */
+               rc = get_parameters(lbuf, param, 1);
+               if ((param[0] <= 0xFF) && (rc == 0))
+               {
+                       read_data = rt5025_reg_read(client, param[0]);
+               }
+               else
+                       rc = -EINVAL;
+       }
+
+       if (rc == 0)
+               rc = cnt;
+
+       return rc;
+}
+
+static const struct file_operations reg_debug_ops = {
+       .open = reg_debug_open,
+       .write = reg_debug_write,
+       .read = reg_debug_read
+};
+
+static int __devinit rt5025_debug_probe(struct platform_device *pdev)
+{
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5025_debug_info *di;
+
+       di = kzalloc(sizeof(*di), GFP_KERNEL);
+       if (!di)
+               return -ENOMEM;
+
+       di->i2c = chip->i2c;
+
+       RTINFO("add debugfs for core RT5025");
+       client = chip->i2c;
+       debugfs_rt_dent = debugfs_create_dir("rt5025_dbg", 0);
+       if (!IS_ERR(debugfs_rt_dent)) {
+               debugfs_peek = debugfs_create_file("peek",
+               S_IFREG | S_IRUGO, debugfs_rt_dent,
+               (void *) "peek", &reg_debug_ops);
+
+               debugfs_poke = debugfs_create_file("poke",
+               S_IFREG | S_IRUGO, debugfs_rt_dent,
+               (void *) "poke", &reg_debug_ops);
+       }
+
+       platform_set_drvdata(pdev, di);
+
+       return 0;
+}
+
+static int __devexit rt5025_debug_remove(struct platform_device *pdev)
+{
+       struct rt5025_debug_info *di = platform_get_drvdata(pdev);
+
+       if (!IS_ERR(debugfs_rt_dent))
+               debugfs_remove_recursive(debugfs_rt_dent);
+
+       kfree(di);
+       return 0;
+}
+
+static struct platform_driver rt5025_debug_driver = 
+{
+       .driver = {
+               .name = RT5025_DEVICE_NAME "-debug",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5025_debug_probe,
+       .remove = __devexit_p(rt5025_debug_remove),
+};
+
+static int __init rt5025_debug_init(void)
+{
+       return platform_driver_register(&rt5025_debug_driver);
+}
+subsys_initcall_sync(rt5025_debug_init);
+
+static void __exit rt5025_debug_exit(void)
+{
+       platform_driver_unregister(&rt5025_debug_driver);
+}
+module_exit(rt5025_debug_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Debug driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-debug");
diff --git a/drivers/mfd/rt5025-i2c.c b/drivers/mfd/rt5025-i2c.c
new file mode 100755 (executable)
index 0000000..29961de
--- /dev/null
@@ -0,0 +1,291 @@
+/* drivers/mfd/rt5025-i2c.c
+ * I2C Driver for Richtek RT5025
+ * Multi function device - multi functional baseband PMIC
+ *
+ * Copyright (C) 2013
+ * Author: CY Huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/mfd/rt5025.h>
+
+static inline int rt5025_read_device(struct i2c_client *i2c,
+                                     int reg, int bytes, void *dest)
+{
+       int ret;
+       if (bytes > 1)
+               ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
+       else {
+               ret = i2c_smbus_read_byte_data(i2c, reg);
+               if (ret < 0)
+                       return ret;
+               *(unsigned char *)dest = (unsigned char)ret;
+       }
+
+       return ret;
+}
+
+int rt5025_reg_block_read(struct i2c_client *i2c, \
+                       int reg, int bytes, void *dest)
+{
+       return rt5025_read_device(i2c, reg, bytes, dest);
+}
+EXPORT_SYMBOL(rt5025_reg_block_read);
+#if 0
+int rt5025_reg_read(struct i2c_client *i2c, int reg)
+{
+       struct rt5025_chip* chip = i2c_get_clientdata(i2c);
+       int ret;
+       RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n",
+           (unsigned int)i2c,(unsigned int)reg);
+       mutex_lock(&chip->io_lock);
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(rt5025_reg_read);
+
+int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data)
+{
+       struct rt5025_chip* chip = i2c_get_clientdata(i2c);
+       int ret;
+       printk("%s,line=%d\n", __func__,__LINE__);
+
+//     RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n",
+ //          (unsigned int)i2c,(unsigned int)reg,(unsigned int)data);
+       mutex_lock(&chip->io_lock);
+printk("%s,line=%d \n", __func__,__LINE__);
+
+       ret = i2c_smbus_write_byte_data(i2c, reg, data);
+       mutex_unlock(&chip->io_lock);
+       printk("%s,line=%d %d \n", __func__,__LINE__,ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(rt5025_reg_write);
+#else
+int rt5025_reg_read(struct i2c_client *i2c, int reg)
+{
+    struct i2c_adapter *adap;
+    struct i2c_msg msgs[2];
+    int ret;
+    unsigned char *dest;
+    u8 val;
+       
+    dest = &val;
+
+    if(!i2c)
+               return ret;
+  
+    adap = i2c->adapter;               
+    
+    msgs[0].addr = i2c->addr;
+    msgs[0].buf = &reg;
+    msgs[0].flags = i2c->flags;
+    msgs[0].len = 1;
+    msgs[0].scl_rate = 200*1000;
+    
+     msgs[1].buf = dest;
+    msgs[1].addr = i2c->addr;
+    msgs[1].flags = i2c->flags | I2C_M_RD;
+    msgs[1].len = 1;
+    msgs[1].scl_rate = 200*1000;
+    ret = i2c_transfer(adap, msgs, 2);
+
+//     printk("***run in %s %d msgs[1].buf = %d\n",__FUNCTION__,__LINE__,*(msgs[1].buf));
+
+       return val;   
+}
+EXPORT_SYMBOL(rt5025_reg_read);
+
+int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data)
+{
+       
+       int ret=-1;
+       
+       struct i2c_adapter *adap;
+       struct i2c_msg msg;
+       char tx_buf[2];
+
+       if(!i2c)
+               return ret;
+    
+       adap = i2c->adapter;            
+       tx_buf[0] = reg;
+       tx_buf[1] = data;
+       
+       msg.addr = i2c->addr;
+       msg.buf = &tx_buf[0];
+       msg.len = 1 +1;
+       msg.flags = i2c->flags;   
+       msg.scl_rate = 200*1000;        
+
+       ret = i2c_transfer(adap, &msg, 1);
+       return ret;     
+}
+EXPORT_SYMBOL(rt5025_reg_write);
+#endif
+int rt5025_assign_bits(struct i2c_client *i2c, int reg,
+               unsigned char mask, unsigned char data)
+{
+       struct rt5025_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char value;
+       int ret;
+       mutex_lock(&chip->io_lock);
+
+       ret = rt5025_read_device(i2c, reg, 1, &value);
+
+       if (ret < 0)
+               goto out;
+       value &= ~mask;
+       value |= (data&mask);
+       ret = rt5025_reg_write(i2c,reg,value);
+out:
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(rt5025_assign_bits);
+
+int rt5025_set_bits(struct i2c_client *i2c, int reg,
+               unsigned char mask)
+{
+       return rt5025_assign_bits(i2c,reg,mask,mask);
+}
+EXPORT_SYMBOL(rt5025_set_bits);
+
+int rt5025_clr_bits(struct i2c_client *i2c, int reg,
+               unsigned char mask)
+{
+       return rt5025_assign_bits(i2c,reg,mask,0);
+}
+EXPORT_SYMBOL(rt5025_clr_bits);
+
+static int __devinit rt5025_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct rt5025_platform_data *pdata = client->dev.platform_data;
+       struct rt5025_chip *chip;
+       int ret = 0;
+       u8 val;
+
+       if (!pdata)
+               return -EINVAL;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->irq = client->irq;
+       chip->i2c = client;
+       chip->dev = &client->dev;
+
+#if 0
+       if (pdata->event_callback)
+       {
+               chip->event_callback = kzalloc(sizeof(struct rt5025_event_callback), GFP_KERNEL);
+               memcpy(chip->event_callback, pdata->event_callback, sizeof(struct rt5025_event_callback));
+       }
+#endif /* #if 0 */
+
+       i2c_set_clientdata(client, chip);
+       mutex_init(&chip->io_lock);
+       
+       rt5025_read_device(client,0x00,1,&val);
+       if (val != 0x81){
+       printk("The PMIC is not RT5025\n");
+       return 0;
+       }
+       ret = rt5025_core_init(chip, pdata);
+       if (ret < 0)
+               dev_err(chip->dev, "rt5025_core_init_fail\n");
+       else
+               pr_info("RT5025 Initialize successfully\n");
+
+       if (pdata && pdata->pre_init) {
+               ret = pdata->pre_init(chip);
+               if (ret != 0) {
+                       dev_err(chip->dev, "pre_init() failed: %d\n", ret);
+               }
+       }
+       
+       if (pdata && pdata->post_init) {
+               ret = pdata->post_init();
+               if (ret != 0) {
+                       dev_err(chip->dev, "post_init() failed: %d\n", ret);
+               }
+       }
+
+       return ret;
+
+}
+
+static int __devexit rt5025_i2c_remove(struct i2c_client *client)
+{
+       struct rt5025_chip *chip = i2c_get_clientdata(client);
+       rt5025_core_deinit(chip);
+       #if 0
+       if (chip->event_callback)
+               kfree(chip->event_callback);a
+       #endif
+       kfree(chip);
+       return 0;
+}
+
+static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct rt5025_chip *chip = i2c_get_clientdata(client);
+       chip->suspend = 1;
+       return 0;
+}
+
+static int rt5025_i2c_resume(struct i2c_client *client)
+{
+       struct rt5025_chip *chip = i2c_get_clientdata(client);
+       chip->suspend = 0;
+       return 0;
+}
+
+static const struct i2c_device_id rt5025_id_table[] = {
+       { RT5025_DEVICE_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, rt5025_id_table);
+
+static struct i2c_driver rt5025_driver = {
+       .driver = {
+               .name   = RT5025_DEVICE_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = rt5025_i2c_probe,
+       .remove         = __devexit_p(rt5025_i2c_remove),
+       .suspend        = rt5025_i2c_suspend,
+       .resume         = rt5025_i2c_resume,
+       .id_table       = rt5025_id_table,
+};
+
+static int __init rt5025_i2c_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&rt5025_driver);
+       if (ret != 0)
+               pr_err("Failed to register RT5025 I2C driver: %d\n", ret);
+       return ret;
+}
+subsys_initcall_sync(rt5025_i2c_init);
+
+static void __exit rt5025_i2c_exit(void)
+{
+       i2c_del_driver(&rt5025_driver);
+}
+module_exit(rt5025_i2c_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("I2C Driver for Richtek RT5025");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
diff --git a/drivers/mfd/rt5025-irq.c b/drivers/mfd/rt5025-irq.c
new file mode 100755 (executable)
index 0000000..82535e9
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  drivers/mfd/rt5025-irq.c
+ *  Driver foo Richtek RT5025 PMIC irq
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-irq.h>
+
+struct rt5025_irq_info {
+       struct i2c_client *i2c;
+       struct device *dev;
+       struct rt5025_chip *chip;
+       struct workqueue_struct *wq;
+       struct rt5025_event_callback *event_cb;
+       struct delayed_work delayed_work;
+       int intr_pin;
+       int irq;
+};
+
+static void rt5025_work_func(struct work_struct *work)
+{
+       struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work);
+       struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(delayed_work, struct rt5025_irq_info, delayed_work);
+       unsigned char irq_stat[10] = {0};
+       uint32_t chg_event = 0, pwr_event = 0;
+
+       if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0)
+       {
+               RTINFO("irq1->%02x, irq2->%02x, irq3->%02x\n", irq_stat[1], irq_stat[3], irq_stat[5]);
+               RTINFO("irq4->%02x, irq5->%02x\n", irq_stat[7], irq_stat[9]);
+               RTINFO("stat value = %02x\n", rt5025_reg_read(ii->i2c, RT5025_REG_CHGSTAT));
+
+               chg_event = irq_stat[1]<<16 | irq_stat[3]<<8 | irq_stat[5];
+               pwr_event = irq_stat[7]<<8 | irq_stat[9];
+               #ifdef CONFIG_POWER_RT5025
+               if (chg_event & CHARGER_DETECT_MASK)
+                       rt5025_power_charge_detect(ii->chip->power_info);
+               #endif /* CONFIG_POWER_RT5025 */
+               if (ii->event_cb)
+               {
+                       if (chg_event)
+                               ii->event_cb->charger_event_callback(chg_event);
+                       if (pwr_event)
+                               ii->event_cb->power_event_callkback(pwr_event);
+               }
+       }
+       else
+               dev_err(ii->dev, "read irq stat io fail\n");
+
+       #ifdef CONFIG_POWER_RT5025
+       rt5025_power_passirq_to_gauge(ii->chip->power_info);
+       #endif /* CONFIG_POWER_RT5025 */
+
+       enable_irq(ii->irq);
+}
+
+static irqreturn_t rt5025_interrupt(int irqno, void *param)
+{
+       struct rt5025_irq_info *ii = (struct rt5025_irq_info *)param;
+
+       disable_irq_nosync(ii->irq);
+       queue_delayed_work(ii->wq, &ii->delayed_work, 0);
+       return IRQ_HANDLED;
+}
+
+static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii)
+{
+       int ret;
+
+       RTINFO("\n");
+       ii->wq = create_workqueue("rt5025_wq");
+       INIT_DELAYED_WORK(&ii->delayed_work, rt5025_work_func);
+
+       if (gpio_is_valid(ii->intr_pin))
+       {
+               ret = gpio_request(ii->intr_pin, "rt5025_interrupt");
+               if (ret)
+                       return ret;
+
+               ret = gpio_direction_input(ii->intr_pin);
+               if (ret)
+                       return ret;
+
+               if (request_irq(ii->irq, rt5025_interrupt, IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED, "RT5025_IRQ", ii))
+               {
+                       dev_err(ii->dev, "couldn't allocate IRQ_NO(%d) !\n", ii->irq);
+                       return -EINVAL;
+               }
+               enable_irq_wake(ii->irq);
+
+               if (!gpio_get_value(ii->intr_pin))
+               {
+                       disable_irq_nosync(ii->irq);
+                       queue_delayed_work(ii->wq, &ii->delayed_work, 0);
+               }
+       }
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static void __devexit rt5025_interrupt_deinit(struct rt5025_irq_info* ii)
+{
+       if (ii->irq)
+               free_irq(ii->irq, ii);
+
+       if (ii->wq)
+       {
+               cancel_delayed_work_sync(&ii->delayed_work);
+               flush_workqueue(ii->wq);
+               destroy_workqueue(ii->wq);
+       }
+}
+
+static int __devinit rt5025_irq_reg_init(struct rt5025_irq_info* ii, struct rt5025_irq_data* irq_data)
+{
+       RTINFO("\n");
+       // will just enable the interrupt that we want
+       rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_data->irq_enable1.val);
+       rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_data->irq_enable2.val);
+       rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_data->irq_enable3.val);
+       rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, irq_data->irq_enable4.val);
+       rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, irq_data->irq_enable5.val);
+       return 0;
+}
+
+static int __devinit rt5025_irq_probe(struct platform_device *pdev)
+{
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5025_platform_data *pdata = chip->dev->platform_data;
+       struct rt5025_irq_info *ii;
+       printk("%s,line=%d\n", __func__,__LINE__);      
+
+       RTINFO("\n");
+       ii = kzalloc(sizeof(*ii), GFP_KERNEL);
+       if (!ii)
+               return -ENOMEM;
+
+       ii->i2c = chip->i2c;
+       ii->dev = &pdev->dev;
+       ii->chip = chip;
+       ii->intr_pin = pdata->intr_pin;
+       ii->irq = gpio_to_irq(pdata->intr_pin);
+       if (pdata->cb)
+               ii->event_cb = pdata->cb;
+
+       rt5025_irq_reg_init(ii, pdata->irq_data);
+       rt5025_interrupt_init(ii);
+
+       platform_set_drvdata(pdev, ii);
+       return 0;
+}
+
+static int __devexit rt5025_irq_remove(struct platform_device *pdev)
+{
+       struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
+
+       rt5025_interrupt_deinit(ii);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver rt5025_irq_driver = 
+{
+       .driver = {
+               .name = RT5025_DEVICE_NAME "-irq",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5025_irq_probe,
+       .remove = __devexit_p(rt5025_irq_remove),
+};
+
+static int __init rt5025_irq_init(void)
+{
+       return platform_driver_register(&rt5025_irq_driver);
+}
+subsys_initcall_sync(rt5025_irq_init);
+
+static void __exit rt5025_irq_exit(void)
+{
+       platform_driver_unregister(&rt5025_irq_driver);
+}
+module_exit(rt5025_irq_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("IRQ driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-irq");
diff --git a/drivers/mfd/rt5025-misc.c b/drivers/mfd/rt5025-misc.c
new file mode 100755 (executable)
index 0000000..83be67c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  drivers/mfd/rt5025-misc.c
+ *  Driver foo Richtek RT5025 PMIC Misc Part
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-misc.h>
+
+struct rt5025_misc_info {
+       struct i2c_client *i2c;
+};
+
+static struct i2c_client *g_shdn;
+void rt5025_power_off(void)
+{
+       rt5025_set_bits(g_shdn, RT5025_SHDNCTRL_REG, RT5025_SHDNCTRL_MASK);
+}
+EXPORT_SYMBOL(rt5025_power_off);
+
+static int __devinit rt5025_misc_reg_init(struct i2c_client *client, struct rt5025_misc_data *md)
+{
+       int ret = 0;
+       
+       rt5025_reg_write(client, RT5025_RESETCTRL_REG, md->RSTCtrl.val);
+       rt5025_assign_bits(client, RT5025_VSYSULVO_REG, RT5025_VSYSOFF_MASK, md->VSYSCtrl.val);
+       rt5025_reg_write(client, RT5025_PWRONCTRL_REG, md->PwrOnCfg.val);
+       rt5025_reg_write(client, RT5025_SHDNCTRL_REG, md->SHDNCtrl.val);
+       rt5025_reg_write(client, RT5025_PWROFFEN_REG, md->PwrOffCond.val);
+
+       return ret;
+}
+
+static int __devinit rt5025_misc_probe(struct platform_device *pdev)
+{
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5025_platform_data *pdata = chip->dev->platform_data;
+       struct rt5025_misc_info *mi;
+       printk("%s,line=%d\n", __func__,__LINE__);      
+
+       mi = kzalloc(sizeof(*mi), GFP_KERNEL);
+       if (!mi)
+               return -ENOMEM;
+
+       mi->i2c = chip->i2c;
+       rt5025_misc_reg_init(mi->i2c, pdata->misc_data);
+
+       //for shutdown control
+       g_shdn = chip->i2c;
+
+       platform_set_drvdata(pdev, mi);
+       return 0;
+}
+
+static int __devexit rt5025_misc_remove(struct platform_device *pdev)
+{
+       struct rt5025_misc_info *mi = platform_get_drvdata(pdev);
+
+       kfree(mi);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver rt5025_misc_driver = 
+{
+       .driver = {
+               .name = RT5025_DEVICE_NAME "-misc",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5025_misc_probe,
+       .remove = __devexit_p(rt5025_misc_remove),
+};
+
+static int __init rt5025_misc_init(void)
+{
+       return platform_driver_register(&rt5025_misc_driver);
+}
+subsys_initcall_sync(rt5025_misc_init);
+
+static void __exit rt5025_misc_exit(void)
+{
+       platform_driver_unregister(&rt5025_misc_driver);
+}
+module_exit(rt5025_misc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Misc driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-misc");
old mode 100644 (file)
new mode 100755 (executable)
index edda96a..1b4a6c1
@@ -369,6 +369,13 @@ config WM8326_VBAT_LOW_DETECTION
 config TWL60xx_VBAT_LOW_DETECTION
        tristate "Support for twl60xx low battery detection."
        default n
+       
+config POWER_RT5025
+       bool "RT5025 Pmic Chip Power Driver"
+       depends on MFD_RT5025
+       default n
+       help
+         Enable RT5025 Power/Gauge part driver.
 
 config CHARGER_SMB347
        tristate "Summit Microelectronics SMB347 Battery Charger"
old mode 100644 (file)
new mode 100755 (executable)
index fdc582a..2513b80
@@ -49,3 +49,4 @@ obj-$(CONFIG_PLAT_RK)         += rk29_charger_display.o
 obj-$(CONFIG_BATTERY_RK30_ADC_FAC)  += rk30_factory_adc_battery.o
 obj-$(CONFIG_CW2015_BATTERY)  += cw2015_battery.o
 obj-$(CONFIG_BATTERY_RICOH619) += ricoh619-battery.o
+obj-$(CONFIG_POWER_RT5025)     += rt5025-power.o rt5025-gauge.o
\ No newline at end of file
diff --git a/drivers/power/rt5025-gauge.c b/drivers/power/rt5025-gauge.c
new file mode 100755 (executable)
index 0000000..34d181e
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ *  rt5025_gauge.c
+ *  fuel-gauge driver
+ *  revision 0.1
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/android_alarm.h>
+#include <linux/mfd/rt5025.h>
+#include <linux/power/rt5025-gauge.h>
+
+#define RT5025_REG_IRQ_CTL                                             0x50
+#define RT5025_REG_IRQ_FLAG                                            0x51
+#define RT5025_REG_VALRT_MAXTH                         0x53
+#define RT5025_REG_VALRT_MIN1TH                                0x54
+#define RT5025_REG_VALRT_MIN2TH                                0x55
+#define RT5025_REG_TALRT_MAXTH                         0x56
+#define RT5025_REG_TALRT_MINTH                         0x57
+#define RT5025_REG_VCELL_MSB                                   0x58
+#define RT5025_REG_VCELL_LSB                                   0x59
+#define RT5025_REG_INT_TEMPERATUE_MSB  0x5B
+#define RT5025_REG_INT_TEMPERATUE_LSB 0x5C
+#define RT5025_REG_EXT_TEMPERATUE_MSB  0x5E
+#define RT5025_REG_EXT_TEMPERATUE_LSB  0x5F
+#define RT5025_REG_TIMER                                                       0x60
+#define RT5025_REG_CHANNEL_MSB         0x62
+#define RT5025_REG_CHANNEL_LSB         0x63
+#define RT5025_REG_CURRENT_MSB                         0x76
+#define RT5025_REG_CURRENT_LSB                         0x77
+#define RT5025_REG_QCHGH_MSB          0x78
+#define RT5025_REG_QCHGH_LSB          0x79
+#define RT5025_REG_QCHGL_MSB          0x7A
+#define RT5025_REG_QCHGL_LSB          0x7B
+#define RT5025_REG_QDCHGH_MSB                                  0x7C
+#define RT5025_REG_QDCHGH_LSB                                  0x7D
+#define RT5025_REG_QDCHGL_MSB                                  0x7E
+#define RT5025_REG_QDCHGL_LSB                                  0x7F
+
+#define IRQ_CTL_BIT_TMX  (1 << 5)
+#define IRQ_CTL_BIT_TMN  (1 << 4)
+#define IRQ_CTL_BIT_VMX  (1 << 2)
+#define IRQ_CTL_BIT_VMN1 (1 << 1)
+#define IRQ_CTL_BIT_VMN2 (1 << 0)
+
+#define IRQ_FLG_BIT_TMX  (1 << 5)
+#define IRQ_FLG_BIT_TMN  (1 << 4)
+#define IRQ_FLG_BIT_VMX  (1 << 2)
+#define IRQ_FLG_BIT_VMN1 (1 << 1)
+#define IRQ_FLG_BIT_VMN2 (1 << 0)
+
+#define CHANNEL_H_BIT_CLRQDCHG  (1 << 7)
+#define CHANNEL_H_BIT_CLRQCHG   (1 << 6)
+
+#define CHANNEL_L_BIT_CADC_EN   (1 << 7)
+#define CHANNEL_L_BIT_INTEMPCH  (1 << 6)
+#define CHANNEL_L_BIT_AINCH     (1 << 2)
+#define CHANNEL_L_BIT_VBATSCH   (1 << 1)
+#define CHANNEL_L_BIT_VADC_EN   (1 << 0)
+
+#define NORMAL_POLL 10  /* 10 sec */
+#define SUSPEND_POLL (30*60) /* 30 min */
+
+#define HIGH_TEMP_THRES        650
+#define HIGH_TEMP_RECOVER      430
+#define LOW_TEMP_THRES (-30)
+#define LOW_TEMP_RECOVER 0
+#define TEMP_ABNORMAL_COUNT    3
+
+#define TALRTMAX_VALUE  0x38 //65.39'C 0x9
+#define TALRTMIN_VALUE  0x11 //-18.75'C 0x17
+#define VALRTMAX_VALUE  0xDC //4297mV
+#define VALRTMIN1_VALUE 0xB8 //3600mV
+#define VALRTMIN2_VALUE 0x99 //3000mV
+#define TRLS_VALUE      55   //5'C
+#define VRLS_VALUE      100  //100mV
+
+#define IRQ_THRES_UNIT 1953
+
+struct rt5025_gauge_chip {
+  struct i2c_client *client;
+  struct rt5025_power_info *info;
+  struct rt5025_gauge_callbacks cb;
+
+       struct power_supply     battery;
+       
+       struct delayed_work monitor_work;
+       struct wake_lock monitor_wake_lock;
+       struct alarm wakeup_alarm;
+       
+       bool    suspend_poll;
+       ktime_t last_poll;
+       
+  /* battery voltage */
+  u16 vcell;
+  /* battery current */
+  s16 curr;
+  /* battery current offset */
+  u8 curr_offset;
+  /* AIN voltage */
+  u16 ain_volt;
+  /* battery external temperature */
+  s16 ext_temp;
+  /* charge coulomb counter */
+  u32 chg_cc;
+  u32 chg_cc_unuse;
+  /* discharge coulomb counter */
+  u32 dchg_cc;
+  u32 dchg_cc_unuse;
+  /* battery capacity */
+  u8 soc;
+  u16 time_interval;
+  u16 pre_gauge_timer;
+    
+  u8 online;
+  u8 status;
+  u8 health;
+
+  /* IRQ flag */
+  u8 irq_flag;
+   
+  /* max voltage IRQ flag */
+  bool max_volt_irq;
+  /* min voltage1 IRQ flag */
+  bool min_volt1_irq;  
+  /* min voltage2 IRQ flag */
+  bool min_volt2_irq;
+  /* max temperature IRQ flag */
+  bool max_temp_irq;
+  /* min temperature IRQ flag */
+  bool min_temp_irq;
+  
+       u8 temp_high_cnt;
+       u8 temp_low_cnt;
+       u8 temp_recover_cnt;
+};
+
+struct rt5025_gauge_chip *chip;
+u8 irq_thres[LAST_TYPE];
+
+void rt5025_set_status(int status)
+{
+  chip->status = status; 
+}
+
+static int rt5025_read_reg(struct i2c_client *client,
+                               u8 reg, u8 *data, u8 len)
+{
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msgs[2];
+       int ret;
+       
+       msgs[0].addr = client->addr;
+       msgs[0].flags = client->flags;
+       msgs[0].len = 1;
+       msgs[0].buf = &reg;
+       msgs[0].scl_rate = 200*1000;
+
+       msgs[1].addr = client->addr;
+       msgs[1].flags = client->flags | I2C_M_RD;
+       msgs[1].len = len;
+       msgs[1].buf = data;
+       msgs[1].scl_rate = 200*1000;
+       
+       ret = i2c_transfer(adap, msgs, 2);
+        
+       return (ret == 2)? len : ret;  
+}
+
+static int rt5025_write_reg(struct i2c_client *client,
+                               u8 reg, u8 *data, u8 len)
+{
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg;
+       int ret;
+       char *tx_buf = (char *)kmalloc(len + 1, GFP_KERNEL);
+       
+       if(!tx_buf)
+               return -ENOMEM;
+       tx_buf[0] = reg;
+       memcpy(tx_buf+1, data, len);
+       
+       msg.addr = client->addr;
+       msg.flags = client->flags;
+       msg.len = len + 1;
+       msg.buf = (char *)tx_buf;
+       msg.scl_rate = 200*1000;        
+       ret = i2c_transfer(adap, &msg, 1);
+       kfree(tx_buf);
+       return (ret == 1) ? len : ret; 
+}
+
+static void rt5025_gauge_alarm(struct alarm *alarm)
+{
+       wake_lock(&chip->monitor_wake_lock);
+       schedule_delayed_work(&chip->monitor_work, 0);
+}
+
+static void rt5025_program_alarm(int seconds)
+{
+       ktime_t low_interval = ktime_set(seconds, 0);
+       ktime_t slack = ktime_set(20, 0);
+       ktime_t next;
+
+       next = ktime_add(chip->last_poll, low_interval);
+       alarm_start_range(&chip->wakeup_alarm, next, ktime_add(next, slack));
+}
+
+static int rt5025_get_property(struct power_supply *psy,
+                           enum power_supply_property psp,
+                           union power_supply_propval *val)
+{
+  switch (psp) {
+    case POWER_SUPPLY_PROP_STATUS:
+      val->intval = chip->status;
+      break;
+    case POWER_SUPPLY_PROP_HEALTH:
+      val->intval = chip->health;
+      break;
+    case POWER_SUPPLY_PROP_PRESENT:
+      val->intval = chip->online;
+      break;
+    case POWER_SUPPLY_PROP_TEMP:
+      val->intval = chip->ext_temp;
+      break;
+    case POWER_SUPPLY_PROP_ONLINE:
+      val->intval = 1;
+      break;
+    case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+      val->intval = chip->vcell * 1000; //uV
+      break;
+    case POWER_SUPPLY_PROP_CURRENT_NOW:
+      val->intval = chip->curr * 1000; //uA
+      break;
+    case POWER_SUPPLY_PROP_CAPACITY:
+      val->intval = chip->soc;
+      if (val->intval > 100)
+                               val->intval = 100;
+      break;
+    case POWER_SUPPLY_PROP_TECHNOLOGY:
+      val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+      break;
+    default:
+      return -EINVAL;
+  }
+  return 0;
+}
+
+static void rt5025_get_vcell(struct i2c_client *client)
+{
+  u8 data[2];
+       
+  if (rt5025_read_reg(client, RT5025_REG_VCELL_MSB, data, 2) < 0){
+    printk(KERN_ERR "%s: Failed to read Voltage\n", __func__);
+  }
+               
+  chip->vcell = ((data[0] << 8) + data[1]) * 61 / 100;
+       chip->curr_offset = (15444 * chip->vcell - 27444000) / 10000;
+               
+  RTINFO("[RT5025] vcell: %d, offset: %d\n", chip->vcell, chip->curr_offset);
+}
+
+static void rt5025_get_current(struct i2c_client *client)
+{
+  u8 data[2];
+  u16 temp;
+  int sign = 0;
+
+  if (rt5025_read_reg(client, RT5025_REG_CURRENT_MSB, data, 2) < 0) {
+    printk(KERN_ERR "%s: Failed to read CURRENT\n", __func__);
+  }
+
+  temp = (data[0]<<8) | data[1];
+  if (data[0] & (1 << 7)) {
+    sign = 1;
+    temp = (((temp & 0x7FFF) * 3125) / 10 + chip->curr_offset) / 1000;
+  }else
+               temp = ((temp * 3125) / 10 - chip->curr_offset) / 1000;
+
+  if (sign)
+    temp *= -1;
+
+       chip->curr = temp;
+  RTINFO("[RT5025] current: %d\n", chip->curr);
+}
+
+static void rt5025_get_external_temp(struct i2c_client *client)
+{
+  u8 data[2];
+  long int temp;
+
+  if (rt5025_read_reg(client, RT5025_REG_EXT_TEMPERATUE_MSB, data, 2) < 0) {
+    printk(KERN_ERR "%s: Failed to read TEMPERATURE\n", __func__);
+  }
+  chip->ain_volt = (data[0] * 256 + data[1]) * 61 / 100;
+  /// Check battery present
+       if (chip->ain_volt < 1150)
+               chip->online = true;
+       else
+               chip->online = false;
+  temp =  (chip->ain_volt * (-91738) + 81521000) / 100000;
+  chip->ext_temp = (int)temp;
+       
+       if (chip->ext_temp >= HIGH_TEMP_THRES) {
+               if (chip->health != POWER_SUPPLY_HEALTH_OVERHEAT)
+                       chip->temp_high_cnt++;
+       } else if (chip->ext_temp <= HIGH_TEMP_RECOVER && chip->ext_temp >= LOW_TEMP_RECOVER) {
+               if (chip->health == POWER_SUPPLY_HEALTH_OVERHEAT ||
+                   chip->health == POWER_SUPPLY_HEALTH_COLD)
+                       chip->temp_recover_cnt++;
+       } else if (chip->ext_temp <= LOW_TEMP_THRES) {
+               if (chip->health != POWER_SUPPLY_HEALTH_COLD)
+                       chip->temp_low_cnt++;
+       } else {
+               chip->temp_high_cnt = 0;
+               chip->temp_low_cnt = 0;
+               chip->temp_recover_cnt = 0;
+       }
+       
+       if (chip->temp_high_cnt >= TEMP_ABNORMAL_COUNT) {
+        chip->health = POWER_SUPPLY_HEALTH_OVERHEAT;
+        chip->temp_high_cnt = 0;
+       } else if (chip->temp_low_cnt >= TEMP_ABNORMAL_COUNT) {
+        chip->health = POWER_SUPPLY_HEALTH_COLD;
+        chip->temp_low_cnt = 0;
+       } else if (chip->temp_recover_cnt >= TEMP_ABNORMAL_COUNT) {
+        chip->health = POWER_SUPPLY_HEALTH_GOOD;
+        chip->temp_recover_cnt = 0;
+       }
+  RTINFO("[RT5025] external temperature: %d\n", chip->ext_temp);
+}
+
+static void rt5025_clear_cc(operation_mode mode)
+{  
+  u8 data[2];
+       
+  if (rt5025_read_reg(chip->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){
+    printk(KERN_ERR "%s: failed to read channel\n", __func__);
+  }
+
+  if (mode == CHG)
+               data[0] = data[0] | CHANNEL_H_BIT_CLRQCHG;
+       else
+               data[0] = data[0] | CHANNEL_H_BIT_CLRQDCHG;
+               
+  if (rt5025_write_reg(chip->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){
+    printk(KERN_ERR "%s: failed to write channel\n", __func__);
+  }
+}
+
+static void rt5025_get_chg_cc(struct i2c_client *client)
+{
+  u8 data[4];
+  u32 qh_old,ql_old,qh_new,ql_new;
+  u32 cc_masec,offset;
+  
+  if (rt5025_read_reg(client, RT5025_REG_QCHGH_MSB, data, 4) < 0){
+    printk(KERN_ERR "%s: Failed to read QCHG\n", __func__);
+  }
+  qh_old = (data[0]<<8) + data[1];
+  ql_old = (data[2]<<8) + data[3];
+  
+  if (rt5025_read_reg(client, RT5025_REG_QCHGH_MSB, data, 4) < 0){
+    printk(KERN_ERR "%s: Failed to read QCHG\n", __func__);
+  }
+  qh_new = (data[0]<<8) + data[1];
+  ql_new = (data[2]<<8) + data[3];
+       
+  if (qh_new > qh_old){
+     cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+  }else if (qh_new == qh_old){
+    if (ql_new >= ql_old){
+      cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+    }else {  
+      cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10;
+               }
+  }    
+  
+       offset = chip->curr_offset * chip->time_interval;
+                         
+  if (cc_masec != 0){
+               cc_masec = (cc_masec - offset) / 1000;
+       }
+
+  RTINFO("[RT5025] chg_cc_mAsec: %d\n", cc_masec);
+
+       chip->chg_cc = (cc_masec + chip->chg_cc_unuse) / 3600;
+  chip->chg_cc_unuse = (cc_masec + chip->chg_cc_unuse) % 3600;
+  RTINFO("[RT5025] chg_cc_mAH: %d\n", chip->chg_cc);
+  rt5025_clear_cc(CHG);
+}
+
+static void rt5025_get_dchg_cc(struct i2c_client *client)
+{
+  u8 data[4];
+  u32 qh_old,ql_old,qh_new,ql_new;
+  u32 cc_masec,offset;
+  
+  if (rt5025_read_reg(client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){
+    printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__);
+  }
+  qh_old = (data[0]<<8) + data[1];
+  ql_old = (data[2]<<8) + data[3];
+  
+  if (rt5025_read_reg(client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){
+    printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__);
+  }
+  qh_new = (data[0]<<8) + data[1];
+  ql_new = (data[2]<<8) + data[3];
+  
+  if (qh_new > qh_old){
+     cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+  }else if (qh_new == qh_old){
+    if (ql_new >= ql_old){
+      cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+    }else {  
+      cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10;
+               }
+  }    
+  
+       offset = chip->curr_offset * chip->time_interval;
+                         
+  if (cc_masec != 0){
+               cc_masec = (cc_masec - offset) / 1000;
+       }
+
+  RTINFO("[RT5025] dchg_cc_mAsec: %d\n", cc_masec);
+
+       chip->dchg_cc = (cc_masec + chip->dchg_cc_unuse) / 3600;
+  chip->dchg_cc_unuse = (cc_masec + chip->dchg_cc_unuse) % 3600;
+  RTINFO("[RT5025] dchg_cc_mAH: %d\n", chip->dchg_cc);
+       rt5025_clear_cc(DCHG);
+}
+
+static void rt5025_get_irq_flag(struct i2c_client *client)
+{
+  u8 data[1];
+
+  if (rt5025_read_reg(client, RT5025_REG_IRQ_FLAG, data, 1) < 0){
+    printk(KERN_ERR "%s: Failed to read irq_flag\n", __func__);
+  }
+               
+  chip->irq_flag = data[0];
+  RTINFO("[RT5025] IRQ_FLG 0x%x\n", chip->irq_flag);
+}
+
+static void rt5025_get_timer(struct i2c_client *client)
+{
+  u8 data[2];
+       u16 gauge_timer;
+       
+  if (rt5025_read_reg(client, RT5025_REG_TIMER, data, 2) < 0){
+    printk(KERN_ERR "%s: Failed to read Timer\n", __func__);
+  }
+               
+  gauge_timer = (data[0] << 8) + data[1];
+  if (gauge_timer > chip->pre_gauge_timer)
+               chip->time_interval = gauge_timer - chip->pre_gauge_timer;
+       else    
+               chip->time_interval = 65536 - chip->pre_gauge_timer + gauge_timer;
+               
+  chip->pre_gauge_timer = gauge_timer;
+  RTINFO("[RT5025] timer %d , interval %d\n", gauge_timer,chip->time_interval);
+}
+
+static void rt5025_get_soc(struct i2c_client *client)
+{
+  chip->soc = 50;
+}
+
+static void rt5025_channel_cc(bool enable)
+{
+  u8 data[1];
+       
+  if (rt5025_read_reg(chip->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+    printk(KERN_ERR "%s: failed to read channel\n", __func__);
+  }
+
+  if (enable){
+    data[0] = data[0] | 0x80;
+  }else { 
+    data[0] = data[0] & 0x7F;
+  }
+    
+  if (rt5025_write_reg(chip->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+    printk(KERN_ERR "%s: failed to write channel\n", __func__);
+  }
+}
+
+static void rt5025_register_init(struct i2c_client *client)
+{  
+  u8 data[1];
+       
+  /* enable the channel of current,qc,ain,vbat and vadc */
+  if (rt5025_read_reg(client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+    printk("%s: failed to read channel\n", __func__);
+  }
+  data[0] = data[0] |
+                                               CHANNEL_L_BIT_CADC_EN |
+                                               CHANNEL_L_BIT_AINCH |
+                                               CHANNEL_L_BIT_VBATSCH |
+                                               CHANNEL_L_BIT_VADC_EN;
+  if (rt5025_write_reg(client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+    printk("%s: failed to write channel\n", __func__);
+  }
+       /* set the alert threshold value */
+       irq_thres[MAXTEMP]  = TALRTMAX_VALUE;
+       irq_thres[MINTEMP]  = TALRTMIN_VALUE;
+       irq_thres[MAXVOLT]  = VALRTMAX_VALUE;
+       irq_thres[MINVOLT1] = VALRTMIN1_VALUE;
+       irq_thres[MINVOLT2] = VALRTMIN2_VALUE;
+       irq_thres[TEMP_RLS] = TRLS_VALUE;
+       irq_thres[VOLT_RLS] = VRLS_VALUE;
+
+       chip->chg_cc_unuse = 0;
+       chip->dchg_cc_unuse = 0;
+       chip->pre_gauge_timer = 0;
+       chip->online = 1;
+       chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       chip->health = POWER_SUPPLY_HEALTH_GOOD;
+  RTINFO("[RT5025] register initialized\n");
+}
+
+static void rt5025_alert_setting(alert_type type, bool enable)
+{
+       u8 data[1];
+       
+  if (rt5025_read_reg(chip->client, RT5025_REG_IRQ_CTL, data, 1) < 0){
+    printk(KERN_ERR "%s: Failed to read CONFIG\n", __func__);
+  }
+
+  if(enable){
+               switch(type){
+                       case MAXTEMP:
+                               data[0] |= IRQ_CTL_BIT_TMX; //Enable max temperature alert
+                               chip->max_temp_irq = true;
+                               RTINFO("Enable min temperature alert");
+                               break;
+                       case MINTEMP:
+                               data[0] |= IRQ_CTL_BIT_TMN; //Enable min temperature alert
+                               chip->min_temp_irq = true;  
+                               RTINFO("Enable max temperature alert");
+                               break;
+                       case MAXVOLT:
+                               data[0] |= IRQ_CTL_BIT_VMX; //Enable max voltage alert
+                               chip->max_volt_irq = true;
+                               RTINFO("Enable max voltage alert");
+                               break;
+                       case MINVOLT1:
+                               data[0] |= IRQ_CTL_BIT_VMN1; //Enable min1 voltage alert        
+                               chip->min_volt1_irq = true;
+                               RTINFO("Enable min1 voltage alert");
+                               break;
+                       case MINVOLT2:
+                               data[0] |= IRQ_CTL_BIT_VMN2; //Enable min2 voltage alert
+                               chip->min_volt2_irq = true;
+                               RTINFO("Enable min2 voltage alert");
+                               break;
+                       default:
+                               break;
+               }
+       }else{
+               switch(type){
+                       case MAXTEMP:
+                               data[0] = data[0] &~ IRQ_CTL_BIT_TMX; //Disable max temperature alert
+                               chip->max_temp_irq = false;
+                               RTINFO("Disable min temperature alert");
+                               break;
+                       case MINTEMP:
+                               data[0] = data[0] &~ IRQ_CTL_BIT_TMN; //Disable min temperature alert
+                               chip->min_temp_irq = false;
+                               RTINFO("Disable max temperature alert");
+                               break;
+                       case MAXVOLT:
+                               data[0] = data[0] &~ IRQ_CTL_BIT_VMX; //Disable max voltage alert
+                               chip->max_volt_irq = false;
+                               RTINFO("Disable max voltage alert");
+                               break;
+                       case MINVOLT1:
+                               data[0] = data[0] &~ IRQ_CTL_BIT_VMN1; //Disable min1 voltage alert     
+                               chip->min_volt1_irq = false;
+                               RTINFO("Disable min1 voltage alert");
+                               break;
+                       case MINVOLT2:
+                               data[0] = data[0] &~ IRQ_CTL_BIT_VMN2; //Disable min2 voltage alert
+                               chip->min_volt2_irq = false;
+                               RTINFO("Disable min2 voltage alert");
+                               break;
+                       default:
+                               break;
+               }
+       }
+  if (rt5025_write_reg(chip->client, RT5025_REG_IRQ_CTL, data, 1) < 0)
+               printk(KERN_ERR "%s: failed to write IRQ control\n", __func__);
+}      
+static void rt5025_alert_threshold_init(struct i2c_client *client)
+{
+  u8 data[1];
+
+  /* TALRT MAX threshold setting */
+  data[0] = irq_thres[MAXTEMP];
+  if (rt5025_write_reg(client, RT5025_REG_TALRT_MAXTH, data, 1) < 0)
+               printk(KERN_ERR "%s: failed to write TALRT MAX threshold\n", __func__); 
+  /* TALRT MIN threshold setting */
+  data[0] = irq_thres[MINTEMP];
+  if (rt5025_write_reg(client, RT5025_REG_TALRT_MINTH, data, 1) < 0)
+               printk(KERN_ERR "%s: failed to write TALRT MIN threshold\n", __func__); 
+  /* VALRT MAX threshold setting */
+  data[0] = irq_thres[MAXVOLT];
+  if (rt5025_write_reg(client, RT5025_REG_VALRT_MAXTH, data, 1) < 0)
+               printk(KERN_ERR "%s: failed to write VALRT MAX threshold\n", __func__); 
+  /* VALRT MIN1 threshold setting */
+  data[0] = irq_thres[MINVOLT1];
+  if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN1TH, data, 1) < 0)
+               printk(KERN_ERR "%s: failed to write VALRT MIN1 threshold\n", __func__);        
+  /* VALRT MIN2 threshold setting */
+  data[0] = irq_thres[MINVOLT2];
+  if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN2TH, data, 1) < 0)
+               printk(KERN_ERR "%s: failed to write VALRT MIN2 threshold\n", __func__);        
+}
+
+static void rt5025_alert_init(struct i2c_client *client)
+{
+  /* Set RT5025 gauge alert configuration */
+  rt5025_alert_threshold_init(client);
+       /* Enable gauge alert function */
+       rt5025_alert_setting(MAXTEMP,true);
+       rt5025_alert_setting(MINTEMP,true);
+       rt5025_alert_setting(MAXVOLT,true);
+       rt5025_alert_setting(MINVOLT1,true);
+       rt5025_alert_setting(MINVOLT2,true);    
+}
+
+void rt5025_irq_handler(void)
+{
+  rt5025_get_irq_flag(chip->client);
+
+  if ((chip->irq_flag) & IRQ_FLG_BIT_TMX){     
+               printk(KERN_INFO "[RT5025]: Min temperature IRQ received\n");
+               rt5025_alert_setting(MAXTEMP,false);
+               chip->max_temp_irq = false;
+       }
+  if ((chip->irq_flag) & IRQ_FLG_BIT_TMN){
+               printk(KERN_INFO "[RT5025]: Max temperature IRQ received\n");
+               rt5025_alert_setting(MINTEMP,false);
+               chip->min_temp_irq = false; 
+       }
+  if ((chip->irq_flag) & IRQ_FLG_BIT_VMX){
+               printk(KERN_INFO "[RT5025]: Max voltage IRQ received\n");
+               rt5025_alert_setting(MAXVOLT,false);
+               chip->max_volt_irq = false;
+       }
+  if ((chip->irq_flag) & IRQ_FLG_BIT_VMN1){
+               printk(KERN_INFO "[RT5025]: Min voltage1 IRQ received\n");
+               rt5025_alert_setting(MINVOLT1,false);
+               chip->min_volt1_irq = false;
+       }
+  if ((chip->irq_flag) & IRQ_FLG_BIT_VMN2){
+               printk(KERN_INFO "[RT5025]: Min voltage2 IRQ received\n");
+               rt5025_alert_setting(MINVOLT2,false);
+               chip->min_volt2_irq = false;
+       }
+       
+       wake_lock(&chip->monitor_wake_lock);
+       schedule_delayed_work(&chip->monitor_work, 0);
+}
+
+static void rt5025_update(struct i2c_client *client)
+{
+  /* Update voltage */
+  rt5025_get_vcell(client);
+  /* Update current */
+  rt5025_get_current(client);
+  /* Update external temperature */
+  rt5025_get_external_temp(client);
+  /* Read timer */
+  rt5025_get_timer(client);
+  /* Update chg cc */
+  rt5025_get_chg_cc(client);
+  /* Update dchg cc */
+  rt5025_get_dchg_cc(client);
+  /* Update SOC */
+  rt5025_get_soc(client);
+
+  if ((chip->max_temp_irq == false) &&
+                (((irq_thres[MAXTEMP] * IRQ_THRES_UNIT) / 100 - chip->ain_volt) > irq_thres[TEMP_RLS])){
+               rt5025_alert_setting(MAXTEMP,true);
+       }else if ((chip->min_temp_irq == false) &&
+                                         ((chip->ain_volt - (irq_thres[MINTEMP] * IRQ_THRES_UNIT) / 100) > irq_thres[TEMP_RLS])){
+               rt5025_alert_setting(MINTEMP,true);
+       }else if ((chip->max_volt_irq == false) &&
+                                       ((((irq_thres[MAXVOLT] * IRQ_THRES_UNIT) / 100) - chip->vcell) > irq_thres[VOLT_RLS])){
+               rt5025_alert_setting(MAXVOLT,true);
+       }else if ((chip->min_volt1_irq == false) &&
+                                       ((chip->vcell - ((irq_thres[MINVOLT1] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){
+               rt5025_alert_setting(MINVOLT1,true);                            
+       }else if ((chip->min_volt2_irq == false) &&
+                                       ((chip->vcell - ((irq_thres[MINVOLT2] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){
+               rt5025_alert_setting(MINVOLT2,true);                                            
+       }
+}
+
+static void rt5025_update_work(struct work_struct *work)
+{
+       unsigned long flags;
+       
+  rt5025_update(chip->client);
+
+  /* Update data to framework */
+  power_supply_changed(&chip->battery);
+  
+       /* prevent suspend before starting the alarm */
+       local_irq_save(flags);
+       chip->last_poll = alarm_get_elapsed_realtime();
+       rt5025_program_alarm(NORMAL_POLL);
+       local_irq_restore(flags);
+
+       wake_unlock(&chip->monitor_wake_lock);
+}
+
+static enum power_supply_property rt5025_battery_props[] = {
+  POWER_SUPPLY_PROP_STATUS,
+  POWER_SUPPLY_PROP_HEALTH,
+  POWER_SUPPLY_PROP_PRESENT,
+  POWER_SUPPLY_PROP_TEMP,
+  POWER_SUPPLY_PROP_ONLINE,
+  POWER_SUPPLY_PROP_VOLTAGE_NOW,
+  POWER_SUPPLY_PROP_CURRENT_NOW,
+  POWER_SUPPLY_PROP_CAPACITY,
+  POWER_SUPPLY_PROP_TECHNOLOGY,
+};
+
+void rt5025_gauge_suspend(void)
+{
+       rt5025_channel_cc(false);
+       cancel_delayed_work(&chip->monitor_work);
+
+  RTINFO("\n");
+}
+
+void rt5025_gauge_resume(void)
+{
+       rt5025_channel_cc(true);
+       wake_lock(&chip->monitor_wake_lock);
+       schedule_delayed_work(&chip->monitor_work, 0);
+  RTINFO("\n");
+}
+
+void rt5025_gauge_remove(void)
+{
+       chip->info->event_callback = NULL;
+       power_supply_unregister(&chip->battery);
+       cancel_delayed_work(&chip->monitor_work);
+       wake_lock_destroy(&chip->monitor_wake_lock);
+       kfree(chip);
+}
+
+int rt5025_gauge_init(struct rt5025_power_info *info)
+{
+       int ret;
+  chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+  if (!chip)
+    return -ENOMEM;
+
+  chip->client = info->i2c;
+  chip->info = info;  
+  chip->battery.name = "rt5025-battery";
+  chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+  chip->battery.get_property = rt5025_get_property;
+  chip->battery.properties = rt5025_battery_props;
+  chip->battery.num_properties = ARRAY_SIZE(rt5025_battery_props);
+
+  ret = power_supply_register(info->dev, &chip->battery);
+  if (ret) {
+    printk(KERN_ERR "[RT5025] power supply register failed\n");
+               goto err_wake_lock;
+  }
+
+  chip->last_poll = alarm_get_elapsed_realtime();
+       alarm_init(&chip->wakeup_alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+               rt5025_gauge_alarm);
+
+       INIT_DELAYED_WORK(&chip->monitor_work, rt5025_update_work);
+       
+       wake_lock_init(&chip->monitor_wake_lock, WAKE_LOCK_SUSPEND,
+                       "rt-battery-monitor");
+  /* enable channel */
+  rt5025_register_init(info->i2c);
+
+       /* enable gauge IRQ */
+  rt5025_alert_init(info->i2c);
+
+       /* register callback functions */
+       chip->cb.rt5025_gauge_irq_handler = rt5025_irq_handler;
+       chip->cb.rt5025_gauge_set_status = rt5025_set_status;
+       chip->cb.rt5025_gauge_suspend = rt5025_gauge_suspend;
+       chip->cb.rt5025_gauge_resume = rt5025_gauge_resume;
+       chip->cb.rt5025_gauge_remove = rt5025_gauge_remove;
+       info->event_callback=&chip->cb;
+
+       //rt_register_gauge_callbacks(info->i2c, &chip->cb);
+       
+       wake_lock(&chip->monitor_wake_lock);
+       schedule_delayed_work(&chip->monitor_work, msecs_to_jiffies(1000));
+
+  return 0;
+
+err_wake_lock:
+       wake_lock_destroy(&chip->monitor_wake_lock);
+       kfree(chip);
+
+       return ret;
+}
diff --git a/drivers/power/rt5025-power.c b/drivers/power/rt5025-power.c
new file mode 100755 (executable)
index 0000000..d37232f
--- /dev/null
@@ -0,0 +1,310 @@
+/* drivers/power/rt5025-power.c
+ * I2C Driver for Richtek RT5025 PMIC
+ * Multi function device - multi functional baseband PMIC Power part
+ *
+ * Copyright (C) 2013
+ * Author: CY Huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/mfd/rt5025.h>
+#include <linux/power/rt5025-power.h>
+#include <linux/power/rt5025-gauge.h>
+#include <linux/delay.h>
+
+
+static enum power_supply_property rt5025_adap_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *rt5025_supply_list[] = {
+       "rt5025-battery",
+};
+
+static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
+{
+       int ret;
+       if (onoff)
+               ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
+       else
+               ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
+       return ret;
+}
+
+static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
+{
+       int ret;
+       if (onoff)
+               ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+       else
+               ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+       return ret;
+}
+
+static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_val)
+{
+       int ret = 0;
+       switch (new_val)
+       {
+               case 0x00:
+                       rt5025_set_charging_current_switch(info->i2c, 1);
+                       rt5025_set_charging_buck(info->i2c, 1);
+                       info->chg_stat = 0x00;
+                       if (info->event_callback)
+                               info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
+                       break;
+               case 0x01:
+                       //rt5025_set_charging_current_switch(info->i2c, 1);
+                       info->chg_stat = 0x01;
+                       if (info->event_callback)
+                               info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
+                       break;
+               case 0x02:
+                       rt5025_set_charging_current_switch(info->i2c, 0);
+                       info->chg_stat = 0x02;
+                       if (info->event_callback)
+                               info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL);
+                       break;
+               case 0x03:
+                       rt5025_set_charging_buck(info->i2c, 0);
+                       rt5025_set_charging_current_switch(info->i2c, 0);
+                       info->chg_stat = 0x03;
+                       if (info->event_callback)
+                               info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
+                       break;
+               default:
+                       break;
+       }
+       return ret;
+}
+
+int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
+{
+       if (info->event_callback)
+               info->event_callback->rt5025_gauge_irq_handler();
+       return 0;
+}
+EXPORT_SYMBOL(rt5025_power_passirq_to_gauge);
+
+int rt5025_power_charge_detect(struct rt5025_power_info *info)
+{
+       int ret = 0;
+       unsigned char chgstatval = 0;
+       unsigned old_usbval, old_acval, old_chgval, new_usbval, new_acval, new_chgval;
+
+       old_acval = info->ac_online;
+       old_usbval = info->usb_online;
+       old_chgval = info->chg_stat;
+       
+       ret = rt5025_reg_read(info->i2c, RT5025_REG_CHGSTAT);
+       if (ret<0)
+       {
+               dev_err(info->dev, "read chg stat reg fail\n");
+               return ret;
+       }
+       chgstatval = ret;
+
+       new_acval = (chgstatval&RT5025_CHG_ACONLINE)>>RT5025_CHG_ACSHIFT;
+       if (old_acval != new_acval)
+       {
+               info->ac_online = new_acval;
+               power_supply_changed(&info->ac);
+       }
+       new_usbval = (chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT;
+       if (old_usbval != new_usbval)
+       {
+               info->usb_online = new_usbval;
+               power_supply_changed(&info->usb);
+       }
+
+       new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT;
+       if (new_acval || new_usbval)
+       {
+               if (old_chgval != new_chgval)
+               {
+                       ret = rt5025_chgstat_changed(info, new_chgval);
+               }
+       }
+       else
+       {
+               rt5025_set_charging_buck(info->i2c, 0);
+               rt5025_set_charging_current_switch(info->i2c, 0);
+               info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
+               if (info->event_callback)
+                       info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(rt5025_power_charge_detect);
+
+static int rt5025_adap_get_props(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct rt5025_power_info *info = dev_get_drvdata(psy->dev->parent);
+       switch(psp)
+       {
+               case POWER_SUPPLY_PROP_ONLINE:
+                       if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+                               val->intval = info->ac_online;
+                       else if (psy->type == POWER_SUPPLY_TYPE_USB)
+                               val->intval = info->usb_online;
+                       else
+                               return -EINVAL;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd)
+{
+       info->ac_online = 0;
+       info->usb_online =0;
+       //init charger buckck & charger current en to disable stat
+       info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
+       if (info->event_callback)
+               info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
+       rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK);
+       udelay(200);
+       //init register setting
+       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL2, pd->CHGControl2.val);
+       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL3, pd->CHGControl3.val);
+       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL4, pd->CHGControl4.val);
+       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL5, pd->CHGControl5.val);
+       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL6, pd->CHGControl6.val);
+       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
+       
+       rt5025_power_charge_detect(info);
+
+       return 0;
+}
+
+static int __devinit rt5025_power_probe(struct platform_device *pdev)
+{
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5025_platform_data *pdata = chip->dev->platform_data;
+       struct rt5025_power_info *pi;
+       int ret = 0;
+       printk("%s,line=%d\n", __func__,__LINE__);      
+
+       pi = kzalloc(sizeof(*pi), GFP_KERNEL);
+       if (!pi)
+               return -ENOMEM;
+
+       pi->i2c = chip->i2c;
+       pi->dev = &pdev->dev;
+
+       ret = rt5025_gauge_init(pi);
+       if (ret)
+               goto out;
+
+       platform_set_drvdata(pdev, pi);
+
+       pi->ac.name = "rt5025-ac";
+       pi->ac.type = POWER_SUPPLY_TYPE_MAINS;
+       pi->ac.supplied_to = rt5025_supply_list;
+       pi->ac.properties = rt5025_adap_props;
+       pi->ac.num_properties = ARRAY_SIZE(rt5025_adap_props);
+       pi->ac.get_property = rt5025_adap_get_props;
+       ret = power_supply_register(&pdev->dev, &pi->ac);
+       if (ret)
+               goto out;
+
+       pi->usb.name = "rt5025-usb";
+       pi->usb.type = POWER_SUPPLY_TYPE_USB;
+       pi->ac.supplied_to = rt5025_supply_list;
+       pi->usb.properties = rt5025_adap_props;
+       pi->usb.num_properties = ARRAY_SIZE(rt5025_adap_props);
+       pi->usb.get_property = rt5025_adap_get_props;
+       ret = power_supply_register(&pdev->dev, &pi->usb);
+       if (ret)
+               goto out_usb;
+
+       rt5025_init_charger(pi, pdata->power_data);
+       chip->power_info = pi;
+
+       return ret;
+out_usb:
+       power_supply_unregister(&pi->ac);
+out:
+       kfree(pi);
+
+       return ret;
+}
+
+static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+
+       if (pi->event_callback)
+               pi->event_callback->rt5025_gauge_suspend();
+       return 0;
+}
+
+static int rt5025_power_resume(struct platform_device *pdev)
+{
+       struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+       if (pi->event_callback)
+               pi->event_callback->rt5025_gauge_resume();
+       return 0;
+}
+
+static int __devexit rt5025_power_remove(struct platform_device *pdev)
+{
+       struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (pi->event_callback)
+               pi->event_callback->rt5025_gauge_remove();
+       power_supply_unregister(&pi->usb);
+       power_supply_unregister(&pi->ac);
+       chip->power_info = NULL;
+       kfree(pi);
+
+       return 0;
+}
+
+static struct platform_driver rt5025_power_driver = 
+{
+       .driver = {
+               .name = RT5025_DEVICE_NAME "-power",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5025_power_probe,
+       .remove = __devexit_p(rt5025_power_remove),
+       .suspend = rt5025_power_suspend,
+       .resume = rt5025_power_resume,
+};
+
+static int __init rt5025_power_init(void)
+{
+       return platform_driver_register(&rt5025_power_driver);
+}
+subsys_initcall_sync(rt5025_power_init);
+
+static void __exit rt5025_power_exit(void)
+{
+       platform_driver_unregister(&rt5025_power_driver);
+}
+module_exit(rt5025_power_exit);
+
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Power/Gauge driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-power");
index b8903982e33ac29bf1525c6e47206f469b5f61d7..5ac3c8d5065ad0b2f63ef8b32c3794ab1421ec3e 100644 (file)
@@ -363,5 +363,10 @@ config REGULATOR_TPS6524X
 
 
 
+config REGULATOR_RT5025
+       bool "Richtek RT5025 PMIC Voltage regulstors"
+       depends on MFD_RT5025
+       help
+         This driver supports voltage regulator in RT5025 PMIC chips.
 endif
 
index 13f27a9f1a710a4454abca927a9e3fb25ccf77c5..62bfb75ef4951b0519ff020107b69f7fbc872aa8 100644 (file)
@@ -54,5 +54,6 @@ obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o
 obj-$(CONFIG_REGULATOR_ACT8931) += act8931.o
 obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
 obj-$(CONFIG_REGULATOR_RICOH619) += ricoh619-regulator.o
+obj-$(CONFIG_REGULATOR_RT5025) += rt5025-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/rt5025-regulator.c b/drivers/regulator/rt5025-regulator.c
new file mode 100755 (executable)
index 0000000..e9192a6
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ *  drivers/regulator/rt5025-regulator.c
+ *  Driver foo Richtek RT5025 PMIC Regulator
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/version.h>
+#include <linux/mfd/rt5025.h>
+#include <linux/regulator/rt5025-regulator.h>
+
+struct rt5025_regulator_info {
+       struct regulator_desc   desc;
+       struct regulator_dev    *regulator;
+       struct i2c_client       *i2c;
+       struct rt5025_chip      *chip;
+       const unsigned int      *vol_output_list;
+       const int               vol_output_size;
+       int     min_uV;
+       int     max_uV;
+       int     vol_reg;
+       int     vol_shift;
+       int     vol_mask;
+       int     enable_bit;
+       int     enable_reg;
+};
+
+//for DCDC1
+static const unsigned int rt5025_vol_output_list1[] =
+{
+        700*1000,  725*1000,  750*1000,  775*1000,  800*1000,  825*1000,  850*1000,  875*1000,
+        900*1000,  925*1000,  950*1000,  975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000,
+       1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000,
+       1300*1000, 1325*1000, 1350*1000, 1375*1000, 1400*1000, 1425*1000, 1450*1000, 1475*1000,
+       1500*1000, 1525*1000, 1550*1000, 1575*1000, 1600*1000, 1625*1000, 1650*1000, 1675*1000,
+       1700*1000, 1725*1000, 1750*1000, 1775*1000, 1800*1000, 1825*1000, 1850*1000, 1875*1000,
+       1900*1000, 1925*1000, 1950*1000, 1975*1000, 2000*2000, 2025*1000, 2050*1000, 2075*1000,
+       2100*1000, 2125*1000, 2150*1000, 2175*1000, 2200*1000, 2225*1000, 2250*1000, 2275*1000,
+};
+#define rt5025_vol_output_size1 ARRAY_SIZE(rt5025_vol_output_list1)
+
+//DCDC2, LDO1, LDO2
+static const unsigned int rt5025_vol_output_list2[] =
+{
+        700*1000,  725*1000,  750*1000,  775*1000,  800*1000,  825*1000,  850*1000,  875*1000,
+        900*1000,  925*1000,  950*1000,  975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000,
+       1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000,
+       1300*1000, 1325*1000, 1350*1000, 1375*1000, 1400*1000, 1425*1000, 1450*1000, 1475*1000,
+       1500*1000, 1525*1000, 1550*1000, 1575*1000, 1600*1000, 1625*1000, 1650*1000, 1675*1000,
+       1700*1000, 1725*1000, 1750*1000, 1775*1000, 1800*1000, 1825*1000, 1850*1000, 1875*1000,
+       1900*1000, 1925*1000, 1950*1000, 1975*1000, 2000*2000, 2025*1000, 2050*1000, 2075*1000,
+       2100*1000, 2125*1000, 2150*1000, 2175*1000, 2200*1000, 2225*1000, 2250*1000, 2275*1000,
+       2300*1000, 2325*1000, 2350*1000, 2375*1000, 2400*1000, 2425*1000, 2450*1000, 2475*1000,
+       2500*1000, 2525*1000, 2550*1000, 2575*1000, 2600*1000, 2625*1000, 2650*1000, 2675*1000,
+       2700*1000, 2725*1000, 2750*1000, 2775*1000, 2800*1000, 2825*1000, 2850*1000, 2875*1000,
+       2900*1000, 2925*1000, 2950*1000, 2975*1000, 3000*1000, 3025*1000, 3050*1000, 3075*1000,
+       3100*1000, 3125*1000, 3150*1000, 3175*1000, 3200*1000, 3225*1000, 3250*1000, 3275*1000,
+       3300*1000, 3325*1000, 3350*1000, 3375*1000, 3400*1000, 3425*1000, 3450*1000, 3475*1000,
+       3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000,
+       3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000,
+};
+#define rt5025_vol_output_size2 ARRAY_SIZE(rt5025_vol_output_list2)
+
+//DCDC3
+static const unsigned int rt5025_vol_output_list3[] =
+{
+        700*1000,  750*1000,  800*1000,  850*1000,  900*1000,  950*1000, 1000*1000, 1050*1000,
+       1100*1000, 1150*1000, 1200*1000, 1250*1000, 1300*1000, 1350*1000, 1400*1000, 1450*1000,
+       1500*1000, 1550*1000, 1600*1000, 1650*1000, 1700*1000, 1750*1000, 1800*1000, 1850*1000,
+       1900*1000, 1950*1000, 2000*1000, 2050*1000, 2100*1000, 2150*1000, 2200*1000, 2250*1000,
+       2300*1000, 2350*1000, 2400*1000, 2450*1000, 2500*1000, 2550*1000, 2600*1000, 2650*1000,
+       2700*1000, 2750*1000, 2800*1000, 2850*1000, 2900*1000, 2950*1000, 3000*1000, 3050*1000,
+       3100*1000, 3150*1000, 3200*1000, 3250*1000, 3300*1000, 3350*1000, 3400*1000, 3450*1000,
+       3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000,
+};
+#define rt5025_vol_output_size3 ARRAY_SIZE(rt5025_vol_output_list3)
+
+//DCDC4
+static const unsigned int rt5025_vol_output_list4[] =
+{
+       4500*1000, 4600*1000, 4700*1000, 4800*1000, 4900*1000, 5000*1000, 5100*1000, 5200*1000,
+       5300*1000, 5400*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000,
+};
+#define rt5025_vol_output_size4 ARRAY_SIZE(rt5025_vol_output_list4)
+
+//LDO3, LDO4, LDO5, LDO6
+static const unsigned int rt5025_vol_output_list5[] = 
+{
+       1000*1000, 1100*1000, 1200*1000, 1300*1000, 1400*1000, 1500*1000, 1600*1000, 1700*1000,
+       1800*1000, 1900*1000, 2000*1000, 2100*1000, 2200*1000, 2300*1000, 2400*1000, 2500*1000,
+       2600*1000, 2700*1000, 2800*1000, 2900*1000, 3000*1000, 3100*1000, 3200*1000, 3300*1000,
+       3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000,
+       3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000,
+};
+#define rt5025_vol_output_size5 ARRAY_SIZE(rt5025_vol_output_list5)
+
+static inline int check_range(struct rt5025_regulator_info *info,
+                             int min_uV, int max_uV)
+{
+       if (min_uV < info->min_uV || min_uV > info->max_uV)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int rt5025_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return (index>=info->vol_output_size)? \
+                -EINVAL: \
+               info->vol_output_list[index ];
+}
+
+//#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38))
+static int rt5025_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       unsigned char data;
+       const int count = info->vol_output_size;
+
+       if (selector>count)
+               return -EINVAL;
+       data = (unsigned char)selector;
+       data <<= info->vol_shift;
+       return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data);
+}
+
+static int rt5025_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+       ret = rt5025_reg_read(info->i2c, info->vol_reg);
+       if (ret < 0)
+               return ret;
+       return (ret & info->vol_mask)  >> info->vol_shift;
+}
+//#else
+static int rt5025_find_voltage(struct regulator_dev *rdev,
+                              int min_uV, int max_uV)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       int i=0;
+       const int count = info->vol_output_size;
+       for (i=0;i<count;i++)
+       {
+               if ((info->vol_output_list[i]>=min_uV)
+                       && (info->vol_output_list[i]<=max_uV))
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static int rt5025_set_voltage(struct regulator_dev *rdev,
+                              int min_uV, int max_uV, unsigned *selector)
+       
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       unsigned char data;
+       if (check_range(info, min_uV, max_uV)) {
+               dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n",
+                       min_uV, max_uV);
+               return -EINVAL;
+       }
+       data = rt5025_find_voltage(rdev,min_uV,max_uV);
+       data <<= info->vol_shift;
+       return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data);
+}
+
+
+static int rt5025_get_voltage(struct regulator_dev *rdev)
+{
+       int ret;
+       ret = rt5025_get_voltage_sel(rdev);
+       if (ret < 0)
+               return ret;
+       return rt5025_list_voltage(rdev, ret );
+
+}
+//#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */
+
+static int rt5025_enable(struct regulator_dev *rdev)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return rt5025_set_bits(info->i2c, info->enable_reg,
+                               info->enable_bit);
+}
+
+static int rt5025_disable(struct regulator_dev *rdev)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return rt5025_clr_bits(info->i2c, info->enable_reg,
+                               info->enable_bit);
+}
+
+static int rt5025_is_enabled(struct regulator_dev *rdev)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = rt5025_reg_read(info->i2c, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       return (ret & (info->enable_bit))?1:0;
+}
+static int rt5025_dcdc_get_mode(struct regulator_dev *rdev)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       int buck = rdev_get_id(rdev) - 0;
+       int ret;
+       uint8_t control;
+       
+       ret = rt5025_reg_read(info->i2c, 0x0c);
+        if (ret < 0) {
+                return ret;
+        }
+       if (buck ==0){
+       control =(ret & 0x80)>>7;
+       }
+       else if (buck ==1){
+       control =(ret & 0x40)>>6;
+       }
+       else if (buck ==2){
+       control =(ret & 0x20)>>5;
+       }
+       else{
+       return -1;
+       }
+       switch (control) {
+       case 0:
+               return REGULATOR_MODE_FAST;
+       case 1:
+               return REGULATOR_MODE_NORMAL;
+       default:
+               return -1;
+       }
+       
+}
+static int rt5025_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+       int buck = rdev_get_id(rdev) - 0;
+       int ret;
+       uint8_t control;
+       
+       ret = rt5025_reg_read(info->i2c, 0x0c);
+       if (buck ==0){
+       control =ret &(~ (1 <<7));
+       }
+       else if (buck ==1){
+       control =ret &(~ (1 <<6));
+       }
+       else if (buck ==2){
+       control =ret &(~ (1 <<5));
+       }
+       else{
+       return -1;
+       }
+       
+       switch(mode)
+       {
+       case REGULATOR_MODE_FAST:
+               return  rt5025_reg_write(info->i2c, 0x0c,control);
+       case REGULATOR_MODE_NORMAL:
+                return rt5025_reg_write(info->i2c, 0x0c,(control | (1 <<(7-buck))));
+       default:
+               printk("error:pmu_rt5025 only powersave pwm & auto mode\n");
+               return -EINVAL;
+       }
+}
+static int rt5025_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,   unsigned int old_selector,
+                                    unsigned int new_selector)
+{
+       int old_volt, new_volt;
+       
+       old_volt = rt5025_list_voltage(rdev, old_selector);
+       if (old_volt < 0)
+               return old_volt;
+       
+       new_volt = rt5025_list_voltage(rdev, new_selector);
+       if (new_volt < 0)
+               return new_volt;
+
+       return DIV_ROUND_UP(abs(old_volt - new_volt), 25000);
+}
+
+static struct regulator_ops rt5025_regulator_ops = {
+       .list_voltage           = rt5025_list_voltage,
+//#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38))
+//     .get_voltage_sel        = rt5025_get_voltage_sel,
+//     .set_voltage_sel        = rt5025_set_voltage_sel,
+//#else
+       .set_voltage            = rt5025_set_voltage,
+       .get_voltage            = rt5025_get_voltage,
+//#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */
+       .enable                 = rt5025_enable,
+       .disable                = rt5025_disable,
+       .is_enabled             = rt5025_is_enabled,
+       .get_mode = rt5025_dcdc_get_mode,
+       .set_mode = rt5025_dcdc_set_mode,
+       .set_voltage_time_sel = rt5025_dcdc_set_voltage_time_sel,
+};
+
+#define RT5025_DCDCVOUT_LIST1 rt5025_vol_output_list1
+#define RT5025_DCDCVOUT_LIST2 rt5025_vol_output_list2
+#define RT5025_DCDCVOUT_LIST3 rt5025_vol_output_list3
+#define RT5025_DCDCVOUT_LIST4 rt5025_vol_output_list4
+#define RT5025_LDOVOUT_LIST1  rt5025_vol_output_list2
+#define RT5025_LDOVOUT_LIST2  rt5025_vol_output_list2
+#define RT5025_LDOVOUT_LIST3  rt5025_vol_output_list5
+#define RT5025_LDOVOUT_LIST4  rt5025_vol_output_list5
+#define RT5025_LDOVOUT_LIST5  rt5025_vol_output_list5
+#define RT5025_LDOVOUT_LIST6  rt5025_vol_output_list5
+
+#define RT5025_DCDCVOUT_SIZE1 rt5025_vol_output_size1
+#define RT5025_DCDCVOUT_SIZE2 rt5025_vol_output_size2
+#define RT5025_DCDCVOUT_SIZE3 rt5025_vol_output_size3
+#define RT5025_DCDCVOUT_SIZE4 rt5025_vol_output_size4
+#define RT5025_LDOVOUT_SIZE1  rt5025_vol_output_size2
+#define RT5025_LDOVOUT_SIZE2  rt5025_vol_output_size2
+#define RT5025_LDOVOUT_SIZE3  rt5025_vol_output_size5
+#define RT5025_LDOVOUT_SIZE4  rt5025_vol_output_size5
+#define RT5025_LDOVOUT_SIZE5  rt5025_vol_output_size5
+#define RT5025_LDOVOUT_SIZE6  rt5025_vol_output_size5
+
+
+#define RT5025_DCDC(_id, min, max)                             \
+{                                                              \
+       .desc   = {                                             \
+               .name   = "rt5025-dcdc" #_id,   \
+               .n_voltages = RT5025_DCDCVOUT_SIZE##_id,        \
+               .ops    = &rt5025_regulator_ops,                \
+               .type   = REGULATOR_VOLTAGE,                    \
+               .id     = RT5025_ID_DCDC##_id,                  \
+               .owner  = THIS_MODULE,                          \
+       },                                                      \
+       .vol_output_list= RT5025_DCDCVOUT_LIST##_id,            \
+       .vol_output_size= RT5025_DCDCVOUT_SIZE##_id,            \
+       .min_uV         = min ,                         \
+       .max_uV         = max ,                         \
+       .vol_reg        = RT5025_DCDCVOUT##_id,                 \
+       .vol_shift      = RT5025_DCDCVOUT_SHIFT##_id,           \
+       .vol_mask       = RT5025_DCDCVOUT_MASK##_id,            \
+       .enable_reg     = RT5025_DCDC_OUTPUT_EN,                \
+       .enable_bit     = RT5025_DCDCEN_MASK##_id,              \
+}
+
+#define RT5025_LDO(_id, min, max)                              \
+{                                                              \
+       .desc   = {                                             \
+               .name   = "rt5025-ldo" #_id,                    \
+               .n_voltages = RT5025_LDOVOUT_SIZE##_id,         \
+               .ops    = &rt5025_regulator_ops,                \
+               .type   = REGULATOR_VOLTAGE,                    \
+               .id     = RT5025_ID_LDO##_id,                   \
+               .owner  = THIS_MODULE,                          \
+       },                                                      \
+       .vol_output_list= RT5025_LDOVOUT_LIST##_id,             \
+       .vol_output_size= RT5025_LDOVOUT_SIZE##_id,             \
+       .min_uV         = min ,                         \
+       .max_uV         = max,                          \
+       .vol_reg        = RT5025_LDOVOUT##_id,                  \
+       .vol_shift      = RT5025_LDOVOUT_SHIFT##_id,            \
+       .vol_mask       = RT5025_LDOVOUT_MASK##_id,             \
+       .enable_reg     = RT5025_LDO_OUTPUT_EN,                 \
+       .enable_bit     = RT5025_LDOEN_MASK##_id,               \
+}
+
+static struct rt5025_regulator_info rt5025_regulator_info[] = 
+{
+       RT5025_DCDC(1,  700000, 2275000),
+       RT5025_DCDC(2,  700000, 3500000),
+       RT5025_DCDC(3,  700000, 3500000),
+       RT5025_DCDC(4, 4500000, 5500000),
+       RT5025_LDO( 1,  700000, 3500000),
+       RT5025_LDO( 2,  700000, 3500000),
+       RT5025_LDO( 3, 1000000, 3300000),
+       RT5025_LDO( 4, 1000000, 3300000),
+       RT5025_LDO( 5, 1000000, 3300000),
+       RT5025_LDO( 6, 1000000, 3300000),
+};
+
+static struct rt5025_regulator_info * __devinit find_regulator_info(int id)
+{
+       struct rt5025_regulator_info *ri;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5025_regulator_info); i++) {
+               ri = &rt5025_regulator_info[i];
+               if (ri->desc.id == id)
+                       return ri;
+       }
+       return NULL;
+}
+
+inline struct regulator_dev* rt5025_regulator_register(struct regulator_desc *regulator_desc,
+            struct device *dev, struct regulator_init_data *init_data,
+            void *driver_data)
+{
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0))
+    struct regulator_config config = {
+        .dev = dev,
+        .init_data = init_data,
+        .driver_data = driver_data,
+    };
+    return regulator_register(&regulator_desc, &config);
+#else
+    return regulator_register(regulator_desc,dev,init_data,driver_data);
+#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) */
+}
+
+static int __devinit rt5025_regulator_probe(struct platform_device *pdev)
+{
+       struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5025_platform_data *pdata = chip->dev->platform_data;
+       struct rt5025_regulator_info *ri;
+       struct regulator_dev *rdev;
+       struct regulator_init_data* init_data;
+
+       ri = find_regulator_info(pdev->id);
+       if (ri == NULL) {
+               dev_err(&pdev->dev, "invalid regulator ID specified\n");
+               return -EINVAL;
+       }
+       init_data = pdata->regulator[pdev->id];
+       if (init_data == NULL) {
+               dev_err(&pdev->dev, "no initializing data\n");
+               return -EINVAL;
+       }
+       ri->i2c = chip->i2c;
+       ri->chip = chip;
+
+       rdev = rt5025_regulator_register(&ri->desc, &pdev->dev,
+                                 init_data, ri);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "failed to register regulator %s\n",
+                               ri->desc.name);
+               return PTR_ERR(rdev);
+       }
+
+       platform_set_drvdata(pdev, rdev);
+
+       return 0;
+}
+
+static int __devexit rt5025_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       regulator_unregister(rdev);
+
+       return 0;
+}
+
+static struct platform_driver rt5025_regulator_driver = 
+{
+       .driver = {
+               .name = RT5025_DEVICE_NAME "-regulator",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5025_regulator_probe,
+       .remove = __devexit_p(rt5025_regulator_remove),
+};
+
+static int __init rt5025_regulator_init(void)
+{
+       return platform_driver_register(&rt5025_regulator_driver);
+}
+subsys_initcall_sync(rt5025_regulator_init);
+
+static void __exit rt5025_regulator_exit(void)
+{
+       platform_driver_unregister(&rt5025_regulator_driver);
+}
+module_exit(rt5025_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Regulator driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-regulator");
diff --git a/include/linux/mfd/rt5025-gpio.h b/include/linux/mfd/rt5025-gpio.h
new file mode 100755 (executable)
index 0000000..0215077
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  include/linux/mfd/rt5025-gpio.h
+ *  Include header file for Richtek RT5025 PMIC GPIO file
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_GPIO_H
+#define __LINUX_RT5025_GPIO_H
+
+#define RT5025_REG_GPIO0 0x1C
+#define RT5025_REG_GPIO1 0x1D
+#define RT5025_REG_GPIO2 0x1E
+
+#define RT5025_GPIO_NR 3
+
+#define RT5025_GPIO_INPUT      0x00
+#define RT5025_GPIO_OUTPUT     0x02
+
+#define RT5025_GPIO_DIRSHIFT 6
+#define RT5025_GPIO_DIRMASK  0xC0
+#define RT5025_GPIO_OVALUESHIFT 4
+#define RT5025_GPIO_OVALUEMASK 0x10
+#define RT5025_GPIO_IVALUEMASK 0x08
+
+#endif /* #ifndef __LINUX_RT5025_GPIO_H */
diff --git a/include/linux/mfd/rt5025-irq.h b/include/linux/mfd/rt5025-irq.h
new file mode 100755 (executable)
index 0000000..96efd61
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *  include/linux/mfd/rt5025-irq.h
+ *  Include header file for Richtek RT5025 PMIC IRQ file
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_IRQ_H
+#define __LINUX_RT5025_IRQ_H
+
+#define RT5025_REG_CHGSTAT     0x01
+
+#define RT5025_REG_IRQEN1      0x30
+#define RT5025_REG_IRQEN2      0x32
+#define RT5025_REG_IRQEN3      0x34
+#define RT5025_REG_IRQEN4      0x36
+#define RT5025_REG_IRQEN5      0x38
+
+#endif /* #ifndef __LINUX_RT5025_IRQ_H */
diff --git a/include/linux/mfd/rt5025-misc.h b/include/linux/mfd/rt5025-misc.h
new file mode 100755 (executable)
index 0000000..dbd7e4e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  include/linux/mfd/rt5025-misc.h
+ *  Include header file for Richtek RT5025 PMIC Misc
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_MISC_H
+#define __LINUX_RT5025_MISC_H
+
+#define RT5025_RESETCTRL_REG   0x15
+#define RT5025_VSYSULVO_REG    0x17
+#define RT5025_PWRONCTRL_REG   0x19
+#define RT5025_SHDNCTRL_REG    0x1A
+#define RT5025_PWROFFEN_REG    0x1B
+
+#define RT5025_SHDNCTRL_MASK   0x80
+#define RT5025_VSYSOFF_MASK    0xE0
+
+#endif /* #ifndef __LINUX_RT5025_MISC_H */
diff --git a/include/linux/mfd/rt5025.h b/include/linux/mfd/rt5025.h
new file mode 100755 (executable)
index 0000000..77e76a4
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ *  include/linux/mfd/rt5025.h
+ *  Include header file for Richtek RT5025 Core file
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_RT5025_H
+#define __LINUX_MFD_RT5025_H
+
+#include <linux/power_supply.h>
+
+#define RT5025_DEVICE_NAME "RT5025"
+
+enum {
+       RT5025_RSTDELAY1_100MS,
+       RT5025_RSTDELAY1_500MS,
+       RT5025_RSTDELAY1_1S,
+       RT5025_RSTDELAY1_2S,
+};
+
+enum {
+       RT5025_RSTDELAY2_100MS,
+       RT5025_RSTDELAY2_500MS,
+       RT5025_RSTDELAY2_1S,
+       RT5025_RSTDELAY2_2S,
+};
+
+enum {
+       RT5025_VOFF_2P8V,
+       RT5025_VOFF_2P9V,
+       RT5025_VOFF_3P0V,
+       RT5025_VOFF_3P1V,
+       RT5025_VOFF_3P2V,
+       RT5025_VOFF_3P3V,
+       RT5025_VOFF_3P4V,
+       RT5025_VOFF_3P5V,
+};
+
+enum {
+       RT5025_STARTIME_100MS,
+       RT5025_STARTIME_1S,
+       RT5025_STARTIME_2S,
+       RT5025_STARTIME_3S,
+};
+
+enum {
+       RT5025_LPRESS_1S,
+       RT5025_LPRESS_1P5S,
+       RT5025_LPRESS_2S,
+       RT5025_LPRESS_2P5S,
+};
+
+enum {
+       RT5025_SHDNPRESS_4S,
+       RT5025_SHDNPRESS_6S,
+       RT5025_SHDNPRESS_8S,
+       RT5025_SHDNPRESS_10S,
+};
+
+enum {
+       RT5025_PGDLY_10MS,
+       RT5025_PGDLY_50MS,
+       RT5025_PGDLY_100MS,
+       RT5025_PGDLY_200MS,
+};
+
+enum {
+       RT5025_SHDNDLY_100MS,
+       RT5025_SHDNDLY_500MS,
+       RT5025_SHDNDLY_1S,
+       RT5025_SHDNDLY_2S,
+};
+
+enum {
+       RT5025_CCCHG_TO_4H,
+       RT5025_CCCHG_TO_6H,
+       RT5025_CCCHG_TO_8H,
+       RT5025_CCCHG_TO_10H,
+};
+
+enum {
+       RT5025_PRECHG_TO_30M,
+       RT5025_PRECHG_TO_40M,
+       RT5025_PRECHG_TO_50M,
+       RT5025_PRECHG_TO_60M,
+};
+
+enum {
+       RT5025_ICC_0P5A,
+       RT5025_ICC_0P6A,
+       RT5025_ICC_0P7A,
+       RT5025_ICC_0P8A,
+       RT5025_ICC_0P9A,
+       RT5025_ICC_1A,
+       RT5025_ICC_1P1A,
+       RT5025_ICC_1P2A,
+       RT5025_ICC_1P3A,
+       RT5025_ICC_1P4A,
+       RT5025_ICC_1P5A,
+       RT5025_ICC_1P6A,
+       RT5025_ICC_1P7A,
+       RT5025_ICC_1P8A,
+       RT5025_ICC_1P9A,
+       RT5025_ICC_2A,
+       RT5025_ICC_MAX,
+};
+
+enum {
+       RT5025_AICR_100MA,
+       RT5025_AICR_500MA,
+       RT5025_AICR_1A,
+       RT5025_AICR_NOLIMIT,
+};
+
+enum {
+       RT5025_DPM_4V,
+       RT5025_DPM_4P25V,
+       RT5025_DPM_4P5V,
+       RT5025_DPM_DIS,
+};
+
+enum {
+       RT5025_VPREC_2V,
+       RT5025_VPREC_2P2V,
+       RT5025_VPREC_2P4V,
+       RT5025_VPREC_2P6V,
+       RT5025_VPREC_2P8V,
+       RT5025_VPREC_3V,
+       RT5025_VPREC_3V_1,
+       RT5025_VPREC_3V_2,
+};
+
+enum {
+       RT5025_IEOC_10P,
+       RT5025_IEOC_20P,
+};
+
+enum {
+       RT5025_IPREC_10P,
+       RT5025_IPREC_20P,
+};
+
+enum {
+       RT5025_ID_DCDC1,
+       RT5025_ID_DCDC2,
+       RT5025_ID_DCDC3,
+       RT5025_ID_DCDC4,
+       RT5025_ID_LDO1,
+       RT5025_ID_LDO2,
+       RT5025_ID_LDO3,
+       RT5025_ID_LDO4,
+       RT5025_ID_LDO5,
+       RT5025_ID_LDO6,
+       RT5025_MAX_REGULATOR,
+};
+
+struct rt5025_power_data {
+       union {
+               struct {
+                       unsigned char Resv1:1;
+                       unsigned char CHGBC_EN:1;
+                       unsigned char TE:1;
+                       unsigned char Resv2:1;
+                       unsigned char CCCHG_TIMEOUT:2;
+                       unsigned char PRECHG_TIMEOUT:2;
+               }bitfield;
+               unsigned char val;
+       }CHGControl2;
+       union {
+               struct {
+                       unsigned char Resv:2;
+                       unsigned char VOREG:6;
+               }bitfield;
+               unsigned char val;
+       }CHGControl3;
+       union {
+               struct {
+                       unsigned char Resv:1;
+                       unsigned char AICR:2;
+                       unsigned char ICC:4;
+                       unsigned char CHG_RST:1;
+               }bitfield;
+               unsigned char val;
+       }CHGControl4;
+       union {
+               struct {
+                       unsigned char Resv1:4;
+                       unsigned char DPM:2;
+                       unsigned char Resv2:2;
+               }bitfield;
+               unsigned char val;
+       }CHGControl5;
+       union {
+               struct {
+                       unsigned char IPREC:1;
+                       unsigned char IEOC:1;
+                       unsigned char VPREC:3;
+                       unsigned char Resv:3;
+               }bitfield;
+               unsigned char val;
+       }CHGControl6;
+       union {
+               struct {
+                       unsigned char Resv1:4;
+                       unsigned char CHGC_EN:1;
+                       unsigned char CHG_DCDC_MODE:1;
+                       unsigned char BATD_EN:1;
+                       unsigned char Resv2:1;
+               }bitfield;
+               unsigned char val;
+       }CHGControl7;
+};
+
+struct rt5025_gpio_data {
+       unsigned gpio_base;
+       unsigned irq_base;
+};
+
+struct rt5025_misc_data {
+       union {
+               struct {
+                       unsigned char Action:2;
+                       unsigned char Delayed1:2;
+                       unsigned char Delayed2:2;
+                       unsigned char Resv:2;
+               }bitfield;
+               unsigned char val;
+       }RSTCtrl;
+       union {
+               struct {
+                       unsigned char Resv:5;
+                       unsigned char VOFF:3;
+               }bitfield;
+               unsigned char val;
+       }VSYSCtrl;
+       union {
+               struct {
+                       unsigned char PG_DLY:2;
+                       unsigned char SHDN_PRESS:2;
+                       unsigned char LPRESS_TIME:2;
+                       unsigned char START_TIME:2;
+               }bitfield;
+               unsigned char val;
+       }PwrOnCfg;
+       union {
+               struct {
+                       unsigned char Resv:4;
+                       unsigned char SHDN_DLYTIME:2;
+                       unsigned char SHDN_TIMING:1;
+                       unsigned char SHDN_CTRL:1;
+               }bitfield;
+               unsigned char val;
+       }SHDNCtrl;
+       union {
+               struct {
+                       unsigned char Resv:2;
+                       unsigned char OT_ENSHDN:1;
+                       unsigned char PWRON_ENSHDN:1;
+                       unsigned char DCDC3LV_ENSHDN:1;
+                       unsigned char DCDC2LV_ENSHDN:1;
+                       unsigned char DCDC1LV_ENSHDN:1;
+                       unsigned char SYSLV_ENSHDN:1;
+               }bitfield;
+               unsigned char val;
+       }PwrOffCond;
+};
+
+struct rt5025_irq_data {
+       union {
+               struct {
+                       unsigned char BATABS:1;
+                       unsigned char Resv1:2;
+                       unsigned char INUSB_PLUGIN:1;
+                       unsigned char INUSBOVP:1;
+                       unsigned char Resv2:1;
+                       unsigned char INAC_PLUGIN:1;
+                       unsigned char INACOVP:1;
+               }bitfield;
+               unsigned char val;
+       }irq_enable1;
+       union {
+               struct {
+                       unsigned char CHTERMI:1;
+                       unsigned char CHBATOVI:1;
+                       unsigned char CHGOODI_INUSB:1;
+                       unsigned char CHBADI_INUSB:1;
+                       unsigned char CHSLPI_INUSB:1;
+                       unsigned char CHGOODI_INAC:1;
+                       unsigned char CHBADI_INAC:1;
+                       unsigned char CHSLPI_INAC:1;
+               }bitfield;
+               unsigned char val;
+       }irq_enable2;
+       union {
+               struct {
+                       unsigned char TIMEOUT_CC:1;
+                       unsigned char TIMEOUT_PC:1;
+                       unsigned char Resv:3;
+                       unsigned char CHVSREGI:1;
+                       unsigned char CHTREGI:1;
+                       unsigned char CHRCHGI:1;
+               }bitfield;
+               unsigned char val;
+       }irq_enable3;
+       union {
+               struct {
+                       unsigned char SYSLV:1;
+                       unsigned char DCDC4LVHV:1;
+                       unsigned char PWRONLP:1;
+                       unsigned char PWRONSP:1;
+                       unsigned char DCDC3LV:1;
+                       unsigned char DCDC2LV:1;
+                       unsigned char DCDC1LV:1;
+                       unsigned char OT:1;
+               }bitfield;
+               unsigned char val;
+       }irq_enable4;
+       union {
+               struct {
+                       unsigned char Resv:1;
+                       unsigned char GPIO0_IE:1;
+                       unsigned char GPIO1_IE:1;
+                       unsigned char GPIO2_IE:1;
+                       unsigned char RESETB:1;
+                       unsigned char PWRONF:1;
+                       unsigned char PWRONR:1;
+                       unsigned char KPSHDN:1;
+               }bitfield;
+               unsigned char val;
+       }irq_enable5;
+};
+
+#define CHG_EVENT_INACOVP      (0x80<<16)
+#define CHG_EVENT_INAC_PLUGIN  (0x40<<16)
+#define CHG_EVENT_INUSBOVP     (0x10<<16)
+#define CHG_EVENT_INUSB_PLUGIN (0x08<<16)
+#define CHG_EVENT_BAT_ABS      (0x01<<16)
+
+#define CHG_EVENT_CHSLPI_INAC  (0x80<<8)
+#define CHG_EVENT_CHBADI_INAC  (0x40<<8)
+#define CHG_EVENT_CHGOODI_INAC (0x20<<8)
+#define CHG_EVENT_CHSLPI_INUSB (0x10<<8)
+#define CHG_EVENT_CHBADI_INUSB (0x08<<8)
+#define CHG_EVENT_CHGOODI_INUSB        (0x04<<8)
+#define CHG_EVENT_CHBATOVI     (0x02<<8)
+#define CHG_EVENT_CHTERMI      (0x01<<8)
+
+#define CHG_EVENT_CHRCHGI      (0x80<<0)
+#define CHG_EVENT_CHTREGI      (0x40<<0)
+#define CHG_EVENT_CHVSREGI     (0x20<<0)
+#define CHG_EVENT_TIMEOUTPC    (0x02<<0)
+#define CHG_EVENT_TIMEOUTCC    (0x01<<0)
+
+#define CHARGER_DETECT_MASK    (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN | \
+                                CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB | \
+                                CHG_EVENT_CHBADI_INAC | CHG_EVENT_CHBADI_INUSB)
+
+#define PWR_EVENT_OTIQ         (0x80<<8)
+#define PWR_EVENT_DCDC1LV      (0x40<<8)
+#define PWR_EVENT_DCDC2LV      (0x20<<8)
+#define PWR_EVENT_DCDC3LV      (0x10<<8)
+#define PWR_EVENT_PWRONSP      (0x08<<8)
+#define PWR_EVENT_PWRONLP      (0x04<<8)
+#define PWR_EVENT_DCDC4LVHV    (0x02<<8)
+#define PWR_EVENT_SYSLV                (0x01<<8)
+
+#define PWR_EVENT_KPSHDN       (0x80<<0)
+#define PWR_EVNET_PWRONR       (0x40<<0)
+#define PWR_EVENT_PWRONF       (0x20<<0)
+#define        PWR_EVENT_RESETB        (0x10<<0)
+#define PWR_EVENT_GPIO2IE      (0x08<<0)
+#define PWR_EVENT_GPIO1IE      (0x04<<0)
+#define PWR_EVENT_GPIO0IE      (0x02<<0)
+
+struct rt5025_event_callback {
+       #if 1
+       void (*charger_event_callback)(uint32_t detected);
+       void (*power_event_callkback)(uint32_t detected);
+       #else
+       void (*over_temperature_callback)(uint8_t detected);
+       void (*charging_complete_callback)(void);
+       void (*over_voltage_callback)(uint8_t detected);
+       void (*under_voltage_callback)(uint8_t detected);
+       void (*charge_fault_callback)(uint8_t detected);
+       void (*charge_warning_callback)(uint8_t detected);
+       #endif
+};
+
+struct rt5025_power_info {
+       struct i2c_client       *i2c;
+       struct device           *dev;
+       struct rt5025_gauge_callbacks *event_callback;
+       struct power_supply     ac;
+       struct power_supply     usb;
+       unsigned                ac_online:1;
+       unsigned                usb_online:1;
+       unsigned                chg_stat:3;
+};
+
+struct rt5025_chip {
+       struct i2c_client *i2c;
+       struct workqueue_struct *wq;
+       struct device *dev;
+       struct rt5025_power_info *power_info;
+       int suspend;
+       int irq;
+       struct delayed_work delayed_work;
+       struct mutex io_lock;
+};
+
+struct rt5025_platform_data {
+       struct regulator_init_data* regulator[RT5025_MAX_REGULATOR];
+       struct rt5025_power_data* power_data;
+       struct rt5025_gpio_data* gpio_data;
+       struct rt5025_misc_data* misc_data;
+       struct rt5025_irq_data* irq_data;
+       struct rt5025_event_callback *cb;
+       int (*pre_init)(struct rt5025_chip *rt5025_chip);
+       /** Called after subdevices are set up */
+       int (*post_init)(void);
+       int intr_pin;
+};
+
+#ifdef CONFIG_MFD_RT5025_MISC
+extern void rt5025_power_off(void);
+#endif /* CONFIG_MFD_RT5025_MISC */
+
+#ifdef CONFIG_POWER_RT5025
+extern int rt5025_gauge_init(struct rt5025_power_info *);
+extern int rt5025_power_passirq_to_gauge(struct rt5025_power_info *);
+extern int rt5025_power_charge_detect(struct rt5025_power_info *);
+#endif /* CONFIG_POEWR_RT5025 */
+
+extern int rt5025_reg_block_read(struct i2c_client *, int, int, void *);
+extern int rt5025_reg_read(struct i2c_client *, int);
+extern int rt5025_reg_write(struct i2c_client *, int, unsigned char);
+extern int rt5025_assign_bits(struct i2c_client *, int, unsigned char, unsigned char);
+extern int rt5025_set_bits(struct i2c_client *, int, unsigned char);
+extern int rt5025_clr_bits(struct i2c_client *, int, unsigned char);
+
+extern int rt5025_core_init(struct rt5025_chip *, struct rt5025_platform_data *);
+extern int rt5025_core_deinit(struct rt5025_chip *);
+
+#ifdef CONFIG_MFD_RT_SHOW_INFO
+#define RTINFO(format, args...) \
+       printk(KERN_INFO "%s:%s() line-%d: " format, RT5025_DEVICE_NAME,__FUNCTION__,__LINE__, ##args)
+#else
+#define RTINFO(format,args...)
+#endif /* CONFIG_MFD_RT_SHOW_INFO */
+
+#endif /* __LINUX_MFD_RT5025_H */
diff --git a/include/linux/power/rt5025-gauge.h b/include/linux/power/rt5025-gauge.h
new file mode 100755 (executable)
index 0000000..4ca38cb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  rt5025_gauge.h
+ *  fuel-gauge driver
+ *  revision 0.1
+ */
+
+#ifndef __LINUX_RT5025_GAUGE_H_
+#define __LINUX_RT5025_GAUGE_H_
+
+#define GPIO_GAUGE_ALERT 4
+
+struct rt5025_gauge_callbacks {
+       void (*rt5025_gauge_irq_handler)(void);
+       void (*rt5025_gauge_set_status)(int status);
+       void (*rt5025_gauge_suspend)(void);
+       void (*rt5025_gauge_resume)(void);
+       void (*rt5025_gauge_remove)(void);
+};
+
+
+typedef enum{
+       CHG,
+       DCHG
+}operation_mode;
+
+typedef enum{
+       MAXTEMP,
+       MINTEMP,
+       MAXVOLT,
+       MINVOLT1,
+       MINVOLT2,
+       TEMP_RLS,
+       VOLT_RLS,
+       LAST_TYPE
+}alert_type;   
+
+#endif  /* #ifndef __LINUX_RT5025_GAUGE_H_ */
diff --git a/include/linux/power/rt5025-power.h b/include/linux/power/rt5025-power.h
new file mode 100755 (executable)
index 0000000..1700ec7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  include/linux/power/rt5025-power.h
+ *  Include header file for Richtek RT5025 Core Power Driver
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_POWER_H
+#define __LINUX_RT5025_POWER_H
+
+#define RT5025_REG_CHGSTAT 0x01
+#define RT5025_REG_CHGCTL2 0x02
+#define RT5025_REG_CHGCTL3 0x03
+#define RT5025_REG_CHGCTL4 0x04
+#define RT5025_REG_CHGCTL5 0x05
+#define RT5025_REG_CHGCTL6 0x06
+#define RT5025_REG_CHGCTL7 0x07
+
+#define RT5025_CHGRST_MASK 0x80
+
+#define RT5025_CHGBUCKEN_MASK 0x02
+#define RT5025_CHGCEN_MASK    0x10
+
+#define RT5025_CHGSTAT_MASK  0x30
+#define RT5025_CHGSTAT_SHIFT 4
+#define RT5025_CHGSTAT_UNKNOWN 0x04
+
+#define RT5025_CHG_ACONLINE   0x02
+#define RT5025_CHG_ACSHIFT    1
+#define RT5025_CHG_USBONLINE  0x01
+#define RT5025_CHG_USBSHIFT   0
+
+#endif /* #ifndef __LINUX_RT5025_POWER_H */
diff --git a/include/linux/regulator/rt5025-regulator.h b/include/linux/regulator/rt5025-regulator.h
new file mode 100755 (executable)
index 0000000..317e3f6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  include/linux/regulator/rt5025-regulator.h
+ *  Include header file to Richtek RT5025 Regulator driver
+ *
+ *  Copyright (C) 2013 Richtek Electronics
+ *  cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_REGULATOR_H
+#define __LINUX_RT5025_REGULATOR_H
+
+#define RT5025_REG_DCDCCTRL1 0x08
+#define RT5025_REG_DCDCCTRL2 0x09
+#define RT5025_REG_DCDCCTRL3 0x0A
+#define RT5025_REG_DCDCCTRL4 0x0B
+#define RT5025_REG_LDOCTRL1  0x0D
+#define RT5025_REG_LDOCTRL2  0x0E
+#define RT5025_REG_LDOCTRL3  0x0F
+#define RT5025_REG_LDOCTRL4  0x10
+#define RT5025_REG_LDOCTRL5  0x11
+#define RT5025_REG_LDOCTRL6  0x12
+#define RT5025_REG_DCDCEN    0x17
+#define RT5025_REG_LDOEN     0x18
+
+#define RT5025_DCDCVOUT1     RT5025_REG_DCDCCTRL1
+#define RT5025_DCDCVOUT2     RT5025_REG_DCDCCTRL2
+#define RT5025_DCDCVOUT3     RT5025_REG_DCDCCTRL3
+#define RT5025_DCDCVOUT4     RT5025_REG_DCDCCTRL4
+#define RT5025_LDOVOUT1      RT5025_REG_LDOCTRL1
+#define RT5025_LDOVOUT2      RT5025_REG_LDOCTRL2
+#define RT5025_LDOVOUT3      RT5025_REG_LDOCTRL3
+#define RT5025_LDOVOUT4      RT5025_REG_LDOCTRL4
+#define RT5025_LDOVOUT5      RT5025_REG_LDOCTRL5
+#define RT5025_LDOVOUT6      RT5025_REG_LDOCTRL6
+
+#define RT5025_DCDCVOUT_SHIFT1    2
+#define RT5025_DCDCVOUT_SHIFT2    1
+#define RT5025_DCDCVOUT_SHIFT3    2
+#define RT5025_DCDCVOUT_SHIFT4   0
+#define RT5025_LDOVOUT_SHIFT1     0
+#define RT5025_LDOVOUT_SHIFT2     0
+#define RT5025_LDOVOUT_SHIFT3     3
+#define RT5025_LDOVOUT_SHIFT4     3
+#define RT5025_LDOVOUT_SHIFT5     3
+#define RT5025_LDOVOUT_SHIFT6     3
+
+#define RT5025_DCDCVOUT_MASK1     0xFC
+#define RT5025_DCDCVOUT_MASK2     0xFE
+#define RT5025_DCDCVOUT_MASK3     0xFC
+#define RT5025_DCDCVOUT_MASK4    0x0F
+#define RT5025_LDOVOUT_MASK1      0x7F
+#define RT5025_LDOVOUT_MASK2      0x7F
+#define RT5025_LDOVOUT_MASK3      0xF8
+#define RT5025_LDOVOUT_MASK4      0xF8
+#define RT5025_LDOVOUT_MASK5      0xF8
+#define RT5025_LDOVOUT_MASK6      0xF8
+
+#define RT5025_DCDC_OUTPUT_EN     RT5025_REG_DCDCEN
+#define RT5025_LDO_OUTPUT_EN      RT5025_REG_LDOEN
+
+#define RT5025_DCDCEN_MASK1       0x01
+#define RT5025_DCDCEN_MASK2       0x02
+#define RT5025_DCDCEN_MASK3       0x04
+#define RT5025_DCDCEN_MASK4      0x08
+#define RT5025_LDOEN_MASK1        0x01
+#define RT5025_LDOEN_MASK2        0x02
+#define RT5025_LDOEN_MASK3        0x04
+#define RT5025_LDOEN_MASK4        0x08
+#define RT5025_LDOEN_MASK5        0x10
+#define RT5025_LDOEN_MASK6        0x20
+
+#endif  /* __LINUX_RT5025_REGULATOR_H */