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>
 #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>
 
 #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
 
 #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[] = {
 
 
 static struct i2c_board_info __initdata i2c1_info[] = {
@@ -2130,6 +2192,16 @@ static struct i2c_board_info __initdata i2c1_info[] = {
        },
 #endif
 
        },
 #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",
 #if defined (CONFIG_RTC_HYM8563)
        {
                .type                   = "rtc_hym8563",
@@ -2438,6 +2510,12 @@ static void rk30_pm_power_off(void)
        }
        #endif
 
        }
        #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);
 }
        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_ACT8846 =3,
        PMIC_TYPE_RK808 =4,
        PMIC_TYPE_RICOH619 =5,
+       PMIC_TYPE_RT5025 =6,
        PMIC_TYPE_MAX,
 };
 extern __sramdata  int g_pmic_type;
        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_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;
 
 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.
        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
 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_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.
          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"
 
 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_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 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"
 
 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_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
 
 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_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
 
 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 */