ricoh619:support pmic ricoh619
author张晴 <zhangqing@rock-chips.com>
Sat, 27 Apr 2013 07:45:44 +0000 (15:45 +0800)
committer张晴 <zhangqing@rock-chips.com>
Sat, 27 Apr 2013 07:45:44 +0000 (15:45 +0800)
24 files changed:
arch/arm/mach-rk30/board-pmu-ricoh619.c [new file with mode: 0644]
arch/arm/mach-rk30/board-rk3168-tb.c [changed mode: 0755->0644]
arch/arm/plat-rk/include/plat/board.h
drivers/input/misc/Kconfig [changed mode: 0755->0644]
drivers/input/misc/Makefile [changed mode: 0755->0644]
drivers/input/misc/ricoh619-pwrkey.c [new file with mode: 0644]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ricoh619-irq.c [new file with mode: 0644]
drivers/mfd/ricoh619.c [new file with mode: 0644]
drivers/power/Kconfig [changed mode: 0755->0644]
drivers/power/Makefile
drivers/power/ricoh619-battery.c [new file with mode: 0644]
drivers/regulator/Kconfig [changed mode: 0755->0644]
drivers/regulator/Makefile [changed mode: 0755->0644]
drivers/regulator/ricoh619-regulator.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ricoh619.c [new file with mode: 0644]
include/linux/mfd/ricoh619.h [new file with mode: 0644]
include/linux/power/ricoh619_battery.h [new file with mode: 0644]
include/linux/power/ricoh61x_battery_init.h [new file with mode: 0644]
include/linux/regulator/ricoh619-regulator.h [new file with mode: 0755]
include/linux/rtc/rtc-ricoh619.h [new file with mode: 0755]

diff --git a/arch/arm/mach-rk30/board-pmu-ricoh619.c b/arch/arm/mach-rk30/board-pmu-ricoh619.c
new file mode 100644 (file)
index 0000000..bc9ffb4
--- /dev/null
@@ -0,0 +1,556 @@
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/regulator/ricoh619-regulator.h>
+#include <linux/power/ricoh619_battery.h>
+#include <linux/rtc/rtc-ricoh619.h>
+#include <mach/sram.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+
+#ifdef CONFIG_MFD_RICOH619
+
+static struct ricoh619 *Ricoh619;
+static int ricoh619_pre_init(struct ricoh619 *ricoh619){
+
+       Ricoh619 =      ricoh619;
+       printk("%s,line=%d\n", __func__,__LINE__);      
+       uint8_t cont;
+       int ret;
+
+       ret = ricoh619_clr_bits(ricoh619->dev,RICOH619_PWR_REP_CNT,(1 << 0));  //set restart when power off
+
+       /**********set dcdc mode when in sleep mode **************/
+       
+       /*****************************************************/
+
+       return 0;
+  }
+static int ricoh619_post_init(struct ricoh619 *ricoh619)
+{
+       struct regulator *dcdc;
+       struct regulator *ldo;
+       int i = 0,ret=0;
+       printk("%s,line=%d\n", __func__,__LINE__);
+
+       #ifndef CONFIG_RK_CONFIG
+       g_pmic_type = PMIC_TYPE_RICOH619;
+       #endif
+       printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type);
+       
+       for(i = 0; i < ARRAY_SIZE(ricoh619_dcdc_info); i++)
+       {
+
+                if(ricoh619_dcdc_info[i].min_uv == 0 && ricoh619_dcdc_info[i].max_uv == 0)
+                        continue;
+               dcdc =regulator_get(NULL, ricoh619_dcdc_info[i].name);
+               regulator_set_voltage(dcdc, ricoh619_dcdc_info[i].min_uv, ricoh619_dcdc_info[i].max_uv);
+                regulator_set_suspend_voltage(dcdc, ricoh619_dcdc_info[i].suspend_vol);
+                regulator_set_mode(dcdc, REGULATOR_MODE_NORMAL);
+               regulator_enable(dcdc);
+               printk("%s  %s =%duV end\n", __func__,ricoh619_dcdc_info[i].name, regulator_get_voltage(dcdc));
+               regulator_put(dcdc);
+               udelay(100);
+       }
+       
+       for(i = 0; i < ARRAY_SIZE(ricoh619_ldo_info); i++)
+       {
+                if(ricoh619_ldo_info[i].min_uv == 0 && ricoh619_ldo_info[i].max_uv == 0)
+                        continue;
+               ldo =regulator_get(NULL, ricoh619_ldo_info[i].name);
+               regulator_set_voltage(ldo, ricoh619_ldo_info[i].min_uv, ricoh619_ldo_info[i].max_uv);
+               regulator_enable(ldo);
+               printk("%s  %s =%duV end\n", __func__,ricoh619_ldo_info[i].name, regulator_get_voltage(ldo));
+               regulator_put(ldo);
+       }
+
+               #ifdef CONFIG_RK_CONFIG
+       if(sram_gpio_init(get_port_config(pmic_slp).gpio, &pmic_sleep) < 0){
+               printk(KERN_ERR "sram_gpio_init failed\n");
+               return -EINVAL;
+       }
+       if(port_output_init(pmic_slp, 0, "pmic_slp") < 0){
+               printk(KERN_ERR "port_output_init failed\n");
+               return -EINVAL;
+       }
+       #else
+       if(sram_gpio_init(PMU_POWER_SLEEP, &pmic_sleep) < 0){
+               printk(KERN_ERR "sram_gpio_init failed\n");
+               return -EINVAL;
+       }
+       gpio_request(PMU_POWER_SLEEP, "NULL");
+       gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW);
+               
+       #endif
+       
+       ret = ricoh619_clr_bits(ricoh619->dev,0xb1,(7<< 0));  //set vbatdec voltage  3.0v
+       ret = ricoh619_set_bits(ricoh619->dev,0xb1,(3<< 0));  //set vbatdec voltage 3.0v
+       
+       printk("%s,line=%d END\n", __func__,__LINE__);
+       
+       return 0;
+}
+static struct regulator_consumer_supply ricoh619_dcdc1_supply[] = {
+       {
+               .supply = "ricoh_dc1",
+       },
+       {
+               .supply = "vdd_cpu",
+       },
+       
+};
+static struct regulator_consumer_supply ricoh619_dcdc2_supply[] = {
+       {
+               .supply = "ricoh_dc2",
+       },
+       {
+               .supply = "vdd_core",
+       },
+       
+};
+static struct regulator_consumer_supply ricoh619_dcdc3_supply[] = {
+       {
+               .supply = "ricoh_dc3",
+       },
+};
+
+static struct regulator_consumer_supply ricoh619_dcdc4_supply[] = {
+       {
+               .supply = "ricoh_dc4",
+       },
+};
+
+static struct regulator_consumer_supply ricoh619_dcdc5_supply[] = {
+       {
+               .supply = "ricoh_dc5",
+       },
+};
+
+static struct regulator_consumer_supply ricoh619_ldo1_supply[] = {
+       {
+               .supply = "ricoh_ldo1",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo2_supply[] = {
+       {
+               .supply = "ricoh_ldo2",
+       },
+};
+
+static struct regulator_consumer_supply ricoh619_ldo3_supply[] = {
+       {
+               .supply = "ricoh_ldo3",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo4_supply[] = {
+       {
+               .supply = "ricoh_ldo4",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo5_supply[] = {
+       {
+               .supply = "ricoh_ldo5",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo6_supply[] = {
+       {
+               .supply = "ricoh_ldo6",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo7_supply[] = {
+       {
+               .supply = "ricoh_ldo7",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo8_supply[] = {
+       {
+               .supply = "ricoh_ldo8",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo9_supply[] = {
+       {
+               .supply = "ricoh_ldo9",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldo10_supply[] = {
+       {
+               .supply = "ricoh_ldo10",
+       },
+};
+static struct regulator_consumer_supply ricoh619_ldortc1_supply[] = {
+       {
+               .supply = "ricoh_ldortc1",
+       },
+};
+
+static struct regulator_init_data ricoh619_dcdc1 = {
+       .constraints = {
+               .name           = "RICOH_DC1",
+               .min_uV                 = 600000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc1_supply),
+       .consumer_supplies =  ricoh619_dcdc1_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_dcdc2 = {
+       .constraints = {
+               .name           = "RICOH_DC2",
+               .min_uV                 = 600000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+       
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc2_supply),
+       .consumer_supplies =  ricoh619_dcdc2_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_dcdc3 = {
+       .constraints = {
+               .name           = "RICOH_DC3",
+               .min_uV                 = 600000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc3_supply),
+       .consumer_supplies =  ricoh619_dcdc3_supply,
+};
+
+static struct regulator_init_data ricoh619_dcdc4 = {
+       .constraints = {
+               .name           = "RICOH_DC4",
+               .min_uV                 = 600000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc4_supply),
+       .consumer_supplies =  ricoh619_dcdc4_supply,
+};
+static struct regulator_init_data ricoh619_dcdc5 = {
+       .constraints = {
+               .name           = "RICOH_DC5",
+               .min_uV                 = 600000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc5_supply),
+       .consumer_supplies =  ricoh619_dcdc5_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo1 = {
+       .constraints = {
+               .name           = "RICOH_LDO1",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo1_supply),
+       .consumer_supplies =  ricoh619_ldo1_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo2 = {
+       .constraints = {
+               .name           = "RICOH_LDO2",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo2_supply),
+       .consumer_supplies =  ricoh619_ldo2_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo3 = {
+       .constraints = {
+               .name           = "RICOH_LDO3",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo3_supply),
+       .consumer_supplies =  ricoh619_ldo3_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo4 = {
+       .constraints = {
+               .name           = "RICOH_LDO4",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo4_supply),
+       .consumer_supplies =  ricoh619_ldo4_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo5 = {
+       .constraints = {
+               .name           = "RICOH_LDO5",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo5_supply),
+       .consumer_supplies =  ricoh619_ldo5_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo6 = {
+       .constraints = {
+               .name           = "RICOH_LDO6",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo6_supply),
+       .consumer_supplies =  ricoh619_ldo6_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo7 = {
+       .constraints = {
+               .name           = "RICOH_LDO7",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo7_supply),
+       .consumer_supplies =  ricoh619_ldo7_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo8 = {
+       .constraints = {
+               .name           = "RICOH_LDO8",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo8_supply),
+       .consumer_supplies =  ricoh619_ldo8_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo9 = {
+       .constraints = {
+               .name           = "RICOH_LDO9",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo9_supply),
+       .consumer_supplies =  ricoh619_ldo9_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo10 = {
+       .constraints = {
+               .name           = "RICOH_LDO10",
+               .min_uV                 = 900000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo10_supply),
+       .consumer_supplies =  ricoh619_ldo10_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldortc1 = {
+       .constraints = {
+               .name           = "RICOH_LDORTC1",
+               .min_uV                 = 1700000,
+               .max_uV                 = 3500000,
+               .apply_uV               = 1,
+  
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldortc1_supply),
+       .consumer_supplies =  ricoh619_ldortc1_supply,
+};
+
+static struct ricoh619_battery_platform_data ricoh619_power_battery = {
+       .irq = IRQ_BOARD_BASE,
+       .alarm_vol_mv = 3300,
+       .multiple =0,
+       .monitor_time = 1,
+};
+
+static struct rtc_time rk_time = {     //      2012.1.1 12:00:00 Saturday
+                       .tm_wday = 6,
+                       .tm_year = 111,
+                       .tm_mon = 0,
+                       .tm_mday = 1,
+                       .tm_hour = 12,
+                       .tm_min = 0,
+                       .tm_sec = 0,
+};
+
+static struct ricoh619_rtc_platform_data ricoh619_rtc_data = {
+       .irq = IRQ_BOARD_BASE ,
+       .time = &rk_time,
+};
+
+#define RICOH_REG(_id, _data)  \
+{ \
+               .id = RICOH619_ID_##_id, \
+               .name = "ricoh619-regulator", \
+               .platform_data = _data, \
+} \
+
+static struct ricoh619_pwrkey_platform_data ricoh619_pwrkey_data= { 
+       .irq = IRQ_BOARD_BASE + RICOH619_IRQ_POWER_ON, 
+       .delay_ms = 20, 
+}; 
+
+static struct ricoh619_subdev_info ricoh619_devs[] = {
+       RICOH_REG(DC1, &ricoh619_dcdc1),
+       RICOH_REG(DC2, &ricoh619_dcdc2),
+       RICOH_REG(DC3, &ricoh619_dcdc3),
+       RICOH_REG(DC4, &ricoh619_dcdc4),
+       RICOH_REG(DC5, &ricoh619_dcdc5),
+       
+       RICOH_REG(LDO1, &ricoh619_ldo1),
+       RICOH_REG(LDO2, &ricoh619_ldo2),
+       RICOH_REG(LDO3, &ricoh619_ldo3),
+       RICOH_REG(LDO4, &ricoh619_ldo4),
+       RICOH_REG(LDO5, &ricoh619_ldo5),
+       RICOH_REG(LDO6, &ricoh619_ldo6),
+       RICOH_REG(LDO7, &ricoh619_ldo7),
+       RICOH_REG(LDO8, &ricoh619_ldo8),
+       RICOH_REG(LDO9, &ricoh619_ldo9),
+       RICOH_REG(LDO10, &ricoh619_ldo10),
+       RICOH_REG(LDORTC1, &ricoh619_ldortc1),
+       
+       {                                       
+               .id = 16,  
+               .name ="ricoh619-battery",
+               .platform_data = &ricoh619_power_battery,
+       },
+       
+       {                                       
+               .id = 17,  
+               .name ="rtc_ricoh619",
+               .platform_data = &ricoh619_rtc_data,
+       },
+       
+       {                                       
+               .id = 18,  
+               .name ="ricoh619-pwrkey",
+               .platform_data = &ricoh619_pwrkey_data,
+       },
+       
+};
+
+#define RICOH_GPIO_INIT(_init_apply, _output_mode, _output_val, _led_mode, _led_func)  \
+{  \
+       .output_mode_en = _output_mode,  \
+       .output_val = _output_val,  \
+       .init_apply = _init_apply,   \
+       .led_mode = _led_mode,  \
+       .led_func = _led_func,  \
+}  \
+
+struct ricoh619_gpio_init_data ricoh_gpio_data[] = { 
+       RICOH_GPIO_INIT(0, 1, 0, 0, 1), 
+       RICOH_GPIO_INIT(0, 0, 0, 0, 0), 
+       RICOH_GPIO_INIT(0, 0, 0, 0, 0), 
+       RICOH_GPIO_INIT(0, 0, 0, 0, 0), 
+       RICOH_GPIO_INIT(0, 0, 0, 0, 0), 
+}; 
+
+static struct ricoh619_platform_data ricoh619_data={
+       .irq_base = IRQ_BOARD_BASE,
+//     .init_port  = RICOH619_HOST_IRQ,
+       .num_subdevs    = ARRAY_SIZE(ricoh619_devs),
+       .subdevs        = ricoh619_devs,
+       .pre_init = ricoh619_pre_init,
+       .post_init = ricoh619_post_init,
+       //.gpio_base = RICOH619_GPIO_EXPANDER_BASE, 
+       .gpio_init_data = ricoh_gpio_data, 
+       .num_gpioinit_data = ARRAY_SIZE(ricoh_gpio_data),
+       .enable_shutdown_pin = 0, 
+};
+
+void __sramfunc board_pmu_ricoh619_suspend(void)
+{      
+       #ifdef CONFIG_CLK_SWITCH_TO_32K
+        sram_gpio_set_value(pmic_sleep, GPIO_HIGH);  
+       #endif
+}
+void __sramfunc board_pmu_ricoh619_resume(void)
+{
+       #ifdef CONFIG_CLK_SWITCH_TO_32K
+       sram_gpio_set_value(pmic_sleep, GPIO_LOW);  
+       sram_udelay(2000);
+       #endif
+}
+
+
+#endif
+
+
+
+
old mode 100755 (executable)
new mode 100644 (file)
index 623265c..ede01b6
@@ -47,6 +47,7 @@
 #include <linux/mfd/tps65910.h>
 #include <linux/regulator/act8846.h>
 #include <linux/mfd/rk808.h>
+#include <linux/mfd/ricoh619.h>
 #include <linux/regulator/rk29-pwm-regulator.h>
 
 #ifdef CONFIG_CW2015_BATTERY
@@ -1932,6 +1933,103 @@ static  struct pmu_info  rk808_ldo_info[] = {
 
 #include "board-pmu-rk808.c"
 #endif
+#ifdef CONFIG_MFD_RICOH619
+#define PMU_POWER_SLEEP RK30_PIN0_PA1
+#define RICOH619_HOST_IRQ        RK30_PIN0_PB3
+
+static struct pmu_info  ricoh619_dcdc_info[] = {
+       {
+               .name          = "vdd_cpu",   //arm
+               .min_uv          = 1000000,
+               .max_uv         = 1000000,
+               .suspend_vol  =  900000,
+       },
+       {
+               .name          = "vdd_core",    //logic
+               .min_uv          = 1000000,
+               .max_uv         = 1000000,
+               .suspend_vol  =  900000,
+       },
+       
+       {
+               .name          = "ricoh_dc3",   //vcc18
+               .min_uv          = 1800000,
+               .max_uv         = 1800000,
+               .suspend_vol  =  1800000,
+       },
+       
+       {
+               .name          = "ricoh_dc4",   //vccio
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+               .suspend_vol  =  3300000,
+       },
+
+       {
+               .name          = "ricoh_dc5",   //ddr
+               .min_uv          = 1200000,
+               .max_uv         = 1200000,
+               .suspend_vol  =  1200000,
+       },
+       
+};
+static  struct pmu_info  ricoh619_ldo_info[] = {
+       {
+               .name          = "ricoh_ldo1",   //vcc30
+               .min_uv          = 3000000,
+               .max_uv         = 3000000,
+       },
+       {
+               .name          = "ricoh_ldo2",    //vcca33
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+       },
+       {
+               .name          = "ricoh_ldo3",   //vcctp
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+       },
+       {
+               .name          = "ricoh_ldo4",   //vccsd
+               .min_uv          = 3300000,
+               .max_uv         = 3300000,
+       },
+       {
+               .name          = "ricoh_ldo5",   //vcc18_cif
+               .min_uv          = 1800000,
+               .max_uv         = 1800000,
+       },
+       {
+               .name          = "ricoh_ldo6",   //vdd12
+               .min_uv          = 1200000,
+               .max_uv         = 1200000,
+       },
+       {
+               .name          = "ricoh_ldo7",   //vcc28_cif
+               .min_uv          = 2800000,
+               .max_uv         = 2800000,
+       },
+       {
+               .name          = "ricoh_ldo8",   //vcc25
+               .min_uv          = 2500000,
+               .max_uv         = 2500000,
+       },
+       {
+               .name          = "ricoh_ldo9",   //vdd10
+               .min_uv          = 1000000,
+               .max_uv         = 1000000,
+       },
+       {
+               .name          = "ricoh_ldo10",   //vcca18
+               .min_uv          = 1800000,
+               .max_uv         = 1800000,
+       },      
+       
+ };
+
+#include "board-pmu-ricoh619.c"
+#endif
+
 
 
 static struct i2c_board_info __initdata i2c1_info[] = {
@@ -1973,6 +2071,16 @@ static struct i2c_board_info __initdata i2c1_info[] = {
        },
 #endif
 
+#if defined (CONFIG_MFD_RICOH619)
+       {
+               .type                   = "ricoh619",
+               .addr           = 0x32,
+               .flags                  = 0,
+              .irq            = RICOH619_HOST_IRQ,
+              .platform_data=&ricoh619_data,
+       },
+#endif
+
 #if defined (CONFIG_RTC_HYM8563)
        {
                .type                   = "rtc_hym8563",
@@ -1995,43 +2103,51 @@ static struct i2c_board_info __initdata i2c1_info[] = {
 
 void __sramfunc board_pmu_suspend(void)
 {      
-       #if defined (CONFIG_MFD_WM831X_I2C)
-       if(pmic_is_wm8326())
-       board_pmu_wm8326_suspend();
-       #endif
-       #if defined (CONFIG_MFD_TPS65910)
-       if(pmic_is_tps65910())
-       board_pmu_tps65910_suspend(); 
-    #endif   
-       #if defined (CONFIG_REGULATOR_ACT8846)
-       if(pmic_is_act8846())
-       board_pmu_act8846_suspend(); 
-       #endif   
-       #if defined (CONFIG_MFD_RK808)
-       if(pmic_is_rk808())
-       board_pmu_rk808_suspend();
-       #endif
+#if defined (CONFIG_MFD_WM831X_I2C)
+       if(pmic_is_wm8326())
+       board_pmu_wm8326_suspend();
+#endif
+#if defined (CONFIG_MFD_TPS65910)
+       if(pmic_is_tps65910())
+       board_pmu_tps65910_suspend(); 
+#endif   
+#if defined (CONFIG_REGULATOR_ACT8846)
+       if(pmic_is_act8846())
+       board_pmu_act8846_suspend(); 
+#endif   
+#if defined (CONFIG_MFD_RK808)
+       if(pmic_is_rk808())
+       board_pmu_rk808_suspend();
+#endif
+#if defined (CONFIG_MFD_RICOH619)
+       if(pmic_is_ricoh619())
+       board_pmu_ricoh619_suspend(); 
+#endif 
 
 }
 
 void __sramfunc board_pmu_resume(void)
 {      
-       #if defined (CONFIG_MFD_WM831X_I2C)
-       if(pmic_is_wm8326())
-       board_pmu_wm8326_resume();
-       #endif
-       #if defined (CONFIG_MFD_TPS65910)
-       if(pmic_is_tps65910())
-       board_pmu_tps65910_resume(); 
-       #endif
-       #if defined (CONFIG_REGULATOR_ACT8846)
-       if(pmic_is_act8846())
-       board_pmu_act8846_resume(); 
-       #endif 
-        #if defined (CONFIG_MFD_RK808)
-       if(pmic_is_rk808())
-       board_pmu_rk808_resume();
-       #endif
+#if defined (CONFIG_MFD_WM831X_I2C)
+       if(pmic_is_wm8326())
+       board_pmu_wm8326_resume();
+#endif
+#if defined (CONFIG_MFD_TPS65910)
+       if(pmic_is_tps65910())
+       board_pmu_tps65910_resume(); 
+#endif
+#if defined (CONFIG_REGULATOR_ACT8846)
+       if(pmic_is_act8846())
+       board_pmu_act8846_resume(); 
+#endif 
+#if defined (CONFIG_MFD_RK808)
+       if(pmic_is_rk808())
+       board_pmu_rk808_resume();
+#endif
+#if defined (CONFIG_MFD_RICOH619)
+       if(pmic_is_ricoh619())
+       board_pmu_ricoh619_resume(); 
+#endif  
   
 }
 
@@ -2267,6 +2383,11 @@ static void rk30_pm_power_off(void)
                 rk808_device_shutdown();//rk808 shutdown
         }
         #endif
+        #if defined(CONFIG_MFD_RICOH619) 
+        if(pmic_is_ricoh619()){
+       ricoh619_power_off();    //ricoh619 shutdown
+       }
+       #endif
 
        gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
        while (1);
index 8b41993ba5e460778751ca0d20589da11ac378b8..6bd1ec3f5d5778ebb69d5152e743fcb35f93ccaa 100755 (executable)
@@ -90,6 +90,7 @@ enum {
        PMIC_TYPE_ACT8931 =3,
        PMIC_TYPE_ACT8846 =3,
        PMIC_TYPE_RK808 =4,
+       PMIC_TYPE_RICOH619 =5,
        PMIC_TYPE_MAX,
 };
 extern __sramdata  int g_pmic_type;
@@ -98,6 +99,7 @@ extern __sramdata  int g_pmic_type;
 #define pmic_is_act8931()  (g_pmic_type == PMIC_TYPE_ACT8931)
 #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)
 
 struct  pmu_info {
        char            *name;
old mode 100755 (executable)
new mode 100644 (file)
index b2d165f..7be2f09
@@ -294,6 +294,16 @@ config INPUT_TWL6030_PWRBUTTON
          To compile this driver as a module, choose M here. The module will
          be called twl6030_pwrbutton.
 
+config INPUT_RICOH619_PWRKEY
+       tristate "RICOH RC5T619 PMU PWRKEY driver"
+       depends on MFD_RICOH619
+       default n
+       help
+         If you say yes here you get support for the RICOH RC5T619 PWRKEY module.
+
+         This driver can also be built as a module. If so, the module
+         will be called rc5t619-pwrkey.
+
 config INPUT_TWL4030_VIBRA
        tristate "Support for TWL4030 Vibrator"
        depends on TWL4030_CORE
old mode 100755 (executable)
new mode 100644 (file)
index 59575af..5f33135
@@ -52,3 +52,5 @@ obj-$(CONFIG_INPUT_WM831X_ON)         += wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)        += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
 obj-$(CONFIG_INPUT_LPSENSOR_AL3006)    += al3006.o
+obj-$(CONFIG_INPUT_RICOH619_PWRKEY)    += ricoh619-pwrkey.o
+
diff --git a/drivers/input/misc/ricoh619-pwrkey.c b/drivers/input/misc/ricoh619-pwrkey.c
new file mode 100644 (file)
index 0000000..1663c39
--- /dev/null
@@ -0,0 +1,332 @@
+/*\r
+* driver/input/misc/ricoh619-pwrkey.c\r
+*\r
+* Power Key driver for RICOH RC5T619 power management chip.\r
+*\r
+* Copyright (C) 2012-2013 RICOH COMPANY,LTD\r
+*\r
+*\r
+* This program is free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* This program is distributed in the hope that it will be useful, but WITHOUT\r
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
+* more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+*/\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/errno.h>\r
+#include <linux/input.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/mfd/ricoh619.h>\r
+#include <linux/spinlock.h>\r
+#include <linux/timer.h>\r
+#include <linux/pm.h>\r
+#include <linux/slab.h>\r
+#include <linux/pm_runtime.h>\r
+#include <linux/workqueue.h>\r
+#include <linux/gpio.h>\r
+\r
+#include <linux/mfd/ricoh619.h>\r
+\r
+#define RICOH619_ONKEY_TRIGGER_LEVEL   0\r
+#define RICOH619_ONKEY_OFF_IRQ                         0\r
+\r
+struct ricoh619_pwrkey {\r
+       struct device * dev;\r
+       struct input_dev *pwr;\r
+       #if RICOH619_ONKEY_TRIGGER_LEVEL\r
+               struct timer_list timer;\r
+       #endif\r
+       struct workqueue_struct * workqueue;\r
+       struct work_struct work;\r
+       unsigned long delay;\r
+       int key_irq;\r
+       bool pressed_first;\r
+       struct ricoh619_pwrkey_platform_data *pdata;\r
+       spinlock_t lock;\r
+};\r
+\r
+struct ricoh619_pwrkey *g_pwrkey;\r
+//static int test_set = 0;\r
+\r
+#if RICOH619_ONKEY_TRIGGER_LEVEL\r
+void ricoh619_pwrkey_timer(unsigned long t)\r
+{\r
+       queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
+}\r
+#endif\r
+\r
+extern int pwrkey_wakeup;\r
+static void ricoh619_irq_work(struct work_struct * work)\r
+{\r
+       unsigned long flags;\r
+       uint8_t val;\r
+\r
+//     printk("PMU: %s: \n",__func__);\r
+       //spin_lock_irqsave(&g_pwrkey->lock, flags);\r
+\r
+       if(pwrkey_wakeup){\r
+//             printk("PMU: %s: pwrkey_wakeup\n",__func__);\r
+               pwrkey_wakeup = 0;\r
+               input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
+               input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+               input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
+               input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+               \r
+               return;\r
+       }\r
+       ricoh619_read(g_pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
+       dev_dbg(g_pwrkey->dev, "pwrkey is pressed?(0x%x): 0x%x\n", RICOH619_INT_MON_SYS, val);\r
+//     printk("PMU: %s: val=0x%x\n",__func__,val);\r
+       val &= 0x1;\r
+       if(val){\r
+               #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
+               g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
+               dd_timer(&g_pwrkey->timer);\r
+               #endif\r
+               if (!g_pwrkey->pressed_first){\r
+                       g_pwrkey->pressed_first = true;\r
+//                     printk("PMU1: %s: Power Key!!!\n",__func__);\r
+                       //input_report_key(g_pwrkey->pwr, KEY_POWER, 1);\r
+                       //input_sync(g_pwrkey->pwr);\r
+                       input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
+                       input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+               }\r
+       }\r
+       else{\r
+       if (g_pwrkey->pressed_first){\r
+//                     printk("PMU2: %s: Power Key!!!\n",__func__);\r
+                       //input_report_key(g_pwrkey->pwr, KEY_POWER, 0);\r
+                       //input_sync(g_pwrkey->pwr);\r
+                       input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
+                       input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+               }\r
+               g_pwrkey->pressed_first = false;\r
+       }\r
+\r
+       //spin_unlock_irqrestore(&g_pwrkey->lock, flags);\r
+}\r
+extern struct ricoh619 *g_ricoh619;\r
+static irqreturn_t pwrkey_irq(int irq, void *_pwrkey)\r
+{\r
+//     printk("PMU: %s: \n",__func__);\r
+       struct ricoh619 *ricoh619 = g_ricoh619;\r
+       #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
+       g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
+       add_timer(&g_pwrkey->timer);\r
+       #else\r
+       queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
+       #endif\r
+       ricoh619_clr_bits(g_ricoh619->dev, RICOH619_INT_IR_SYS, 0x1); //clr power-on interrupt\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+#if RICOH619_ONKEY_OFF_IRQ\r
+static irqreturn_t pwrkey_irq_off(int irq, void *_pwrkey)\r
+{\r
+       dev_warn(g_pwrkey->dev, "ONKEY is pressed long time!\n");\r
+       return IRQ_HANDLED;\r
+}\r
+#endif\r
+\r
+static int __devinit ricoh619_pwrkey_probe(struct platform_device *pdev)\r
+{\r
+       struct input_dev *pwr;\r
+       int key_irq;\r
+       int err;\r
+       struct ricoh619_pwrkey *pwrkey;\r
+       struct ricoh619_pwrkey_platform_data *pdata = pdev->dev.platform_data;\r
+       uint8_t val;\r
+\r
+//     printk("PMU: %s: \n",__func__);\r
+\r
+       if (!pdata) {\r
+               dev_err(&pdev->dev, "power key platform data not supplied\n");\r
+               return -EINVAL;\r
+       }\r
+       key_irq = (pdata->irq + RICOH619_IRQ_POWER_ON);\r
+       printk(KERN_INFO "PMU1: %s: key_irq=%d\n", __func__, key_irq);\r
+       pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);\r
+       if (!pwrkey)\r
+               return -ENOMEM;\r
+\r
+       pwrkey->dev = &pdev->dev;\r
+       pwrkey->pdata = pdata;\r
+       pwrkey->pressed_first = false;\r
+       pwrkey->delay = HZ / 1000 * pdata->delay_ms;\r
+       g_pwrkey = pwrkey;\r
+       pwr = input_allocate_device();\r
+       if (!pwr) {\r
+               dev_dbg(&pdev->dev, "Can't allocate power button\n");\r
+               err = -ENOMEM;\r
+               goto free_pwrkey;\r
+       }\r
+       input_set_capability(pwr, EV_KEY, KEY_POWER);\r
+       pwr->name = "ricoh619_pwrkey";\r
+       pwr->phys = "ricoh619_pwrkey/input0";\r
+       pwr->dev.parent = &pdev->dev;\r
+\r
+       #if RICOH619_ONKEY_TRIGGER_LEVEL\r
+       init_timer(&pwrkey->timer);\r
+       pwrkey->timer.function = ricoh619_pwrkey_timer;\r
+       #endif\r
+\r
+       spin_lock_init(&pwrkey->lock);\r
+       err = input_register_device(pwr);\r
+       if (err) {\r
+               dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);\r
+               goto free_input_dev;\r
+       }\r
+       pwrkey->key_irq = key_irq;\r
+       pwrkey->pwr = pwr;\r
+       platform_set_drvdata(pdev, pwrkey);\r
+\r
+       // Check if power-key is pressed at boot up\r
+       err = ricoh619_read(pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
+       if (err < 0) {\r
+               dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",\r
+                                                                        err);\r
+               goto unreg_input_dev;\r
+       }\r
+       val &= 0x1;\r
+       if (val) {\r
+               input_report_key(pwrkey->pwr, KEY_POWER, 1);\r
+//             printk(KERN_INFO "******KEY_POWER:1\n");\r
+               input_sync(pwrkey->pwr);\r
+               pwrkey->pressed_first = true;\r
+       }\r
+\r
+       #if !(RICOH619_ONKEY_TRIGGER_LEVEL)\r
+               ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1); //trigger both edge\r
+       #endif\r
+\r
+       err = request_threaded_irq(key_irq, NULL, pwrkey_irq,\r
+               IRQF_ONESHOT, "ricoh619_pwrkey", pwrkey);\r
+       if (err < 0) {\r
+               dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
+                                                               key_irq, err);\r
+               goto unreg_input_dev;\r
+       }\r
+\r
+       #if RICOH619_ONKEY_OFF_IRQ\r
+       err = request_threaded_irq(key_irq + RICOH619_IRQ_ONKEY_OFF, NULL,\r
+                                               pwrkey_irq_off, IRQF_ONESHOT,\r
+                                               "ricoh619_pwrkey_off", pwrkey);\r
+       if (err < 0) {\r
+               dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
+                       key_irq + RICOH619_IRQ_ONKEY_OFF, err);\r
+               free_irq(key_irq, pwrkey);\r
+               goto unreg_input_dev;\r
+       }\r
+       #endif\r
+\r
+       pwrkey->workqueue = create_singlethread_workqueue("ricoh619_pwrkey");\r
+       INIT_WORK(&pwrkey->work, ricoh619_irq_work);\r
+\r
+       /* Enable power key IRQ */\r
+       /* trigger both edge */\r
+       ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1);\r
+       /* Enable system interrupt */\r
+       ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INTC_INTEN, 0x1);\r
+       /* Enable power-on interrupt */\r
+       ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INT_EN_SYS, 0x1);\r
+//     printk(KERN_INFO "PMU: %s is OK!\n", __func__);\r
+       return 0;\r
+\r
+unreg_input_dev:\r
+       input_unregister_device(pwr);\r
+       pwr = NULL;\r
+\r
+free_input_dev:\r
+       input_free_device(pwr);\r
+       free_pwrkey:\r
+       kfree(pwrkey);\r
+\r
+       return err;\r
+}\r
+\r
+static int __devexit ricoh619_pwrkey_remove(struct platform_device *pdev)\r
+{\r
+       struct ricoh619_pwrkey *pwrkey = platform_get_drvdata(pdev);\r
+\r
+       flush_workqueue(pwrkey->workqueue);\r
+       destroy_workqueue(pwrkey->workqueue);\r
+       free_irq(pwrkey->key_irq, pwrkey);\r
+       input_unregister_device(pwrkey->pwr);\r
+       kfree(pwrkey);\r
+\r
+       return 0;\r
+}\r
+\r
+#ifdef CONFIG_PM\r
+static int ricoh619_pwrkey_suspend(struct device *dev)\r
+{\r
+       struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
+\r
+//     printk(KERN_INFO "PMU: %s\n", __func__);\r
+\r
+       if (info->key_irq)\r
+               disable_irq(info->key_irq);\r
+       cancel_work_sync(&info->work);\r
+       flush_workqueue(info->workqueue);\r
+\r
+       return 0;\r
+}\r
+\r
+static int ricoh619_pwrkey_resume(struct device *dev)\r
+{\r
+       struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
+\r
+//     printk(KERN_INFO "PMU: %s\n", __func__);\r
+       queue_work(info->workqueue, &info->work);\r
+       if (info->key_irq)\r
+               enable_irq(info->key_irq);\r
+\r
+       return 0;\r
+}\r
+\r
+static const struct dev_pm_ops ricoh619_pwrkey_pm_ops = {\r
+       .suspend        = ricoh619_pwrkey_suspend,\r
+       .resume         = ricoh619_pwrkey_resume,\r
+};\r
+#endif\r
+\r
+static struct platform_driver ricoh619_pwrkey_driver = {\r
+       .probe = ricoh619_pwrkey_probe,\r
+       .remove = __devexit_p(ricoh619_pwrkey_remove),\r
+       .driver = {\r
+               .name = "ricoh619-pwrkey",\r
+               .owner = THIS_MODULE,\r
+#ifdef CONFIG_PM\r
+               .pm     = &ricoh619_pwrkey_pm_ops,\r
+#endif\r
+       },\r
+};\r
+\r
+static int __init ricoh619_pwrkey_init(void)\r
+{\r
+       return platform_driver_register(&ricoh619_pwrkey_driver);\r
+}\r
+subsys_initcall_sync(ricoh619_pwrkey_init);\r
+\r
+static void __exit ricoh619_pwrkey_exit(void)\r
+{\r
+       platform_driver_unregister(&ricoh619_pwrkey_driver);\r
+}\r
+module_exit(ricoh619_pwrkey_exit);\r
+\r
+\r
+MODULE_ALIAS("platform:ricoh619-pwrkey");\r
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");\r
+MODULE_DESCRIPTION("ricoh619 Power Key");\r
+MODULE_LICENSE("GPL v2");
\ No newline at end of file
index 6aa29681a06d0173d1a3af59fb6c9110bc17b6e0..5f515c44e69e8e2fa05ea7568befecc1c9638b8d 100644 (file)
@@ -307,6 +307,18 @@ config MFD_RK808
          if you say yes here you get support for the RK808 series of
          Power Management chips.
 
+config MFD_RICOH619
+       bool "Ricoh RC5T619 Power Management system device"
+       depends on I2C && GPIOLIB && GENERIC_HARDIRQS
+       select MFD_CORE
+       default n
+       help
+         If you say yes here you get support for the RICOH619 Power
+         Management system 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 AIC3262_CODEC
        bool "Support TI Codec Aic3262"
        select MFD_CORE
index b810c78978c78edde9afb5d0ca8437f19c0480f8..f076b63518ea6f49d6cd0bfcf52843058d7646df 100644 (file)
@@ -110,3 +110,4 @@ obj-$(CONFIG_TPS65911_COMPARATOR)   += tps65911-comparator.o
 obj-$(CONFIG_MFD_RK610)        += rk610-core.o
 obj-$(CONFIG_MFD_RK808)        += rk808.o rk808-irq.o
 obj-$(CONFIG_MFD_RK616) += rk616-core.o
+obj-$(CONFIG_MFD_RICOH619)     += ricoh619.o ricoh619-irq.o
diff --git a/drivers/mfd/ricoh619-irq.c b/drivers/mfd/ricoh619-irq.c
new file mode 100644 (file)
index 0000000..60e7bb0
--- /dev/null
@@ -0,0 +1,534 @@
+/* 
+ * driver/mfd/ricoh619-irq.c
+ *
+ * Interrupt driver for RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *     Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/ricoh619.h>
+
+
+enum int_type {
+       SYS_INT  = 0x1,
+       DCDC_INT = 0x2,
+       RTC_INT  = 0x4,
+       ADC_INT  = 0x8, 
+       GPIO_INT = 0x10,
+       CHG_INT  = 0x40,
+};
+
+static int gpedge_add[] = {
+       RICOH619_GPIO_GPEDGE1,
+       RICOH619_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+       RICOH619_INT_EN_SYS,
+       RICOH619_INT_EN_DCDC,
+       RICOH619_INT_EN_RTC,
+       RICOH619_INT_EN_ADC1,
+       RICOH619_INT_EN_ADC2,
+       RICOH619_INT_EN_ADC3,
+       RICOH619_INT_EN_GPIO,
+       RICOH619_INT_EN_GPIO2,
+       RICOH619_INT_MSK_CHGCTR,
+       RICOH619_INT_MSK_CHGSTS1,
+       RICOH619_INT_MSK_CHGSTS2,
+       RICOH619_INT_MSK_CHGERR,
+       RICOH619_INT_MSK_CHGEXTIF
+};
+
+static int irq_mon_add[] = {
+       RICOH619_INT_IR_SYS, //RICOH619_INT_MON_SYS,
+       RICOH619_INT_IR_DCDC, //RICOH619_INT_MON_DCDC,
+       RICOH619_INT_IR_RTC, //RICOH619_INT_MON_RTC,
+       RICOH619_INT_IR_ADCL,
+       RICOH619_INT_IR_ADCH,
+       RICOH619_INT_IR_ADCEND,
+       RICOH619_INT_IR_GPIOR,
+       RICOH619_INT_IR_GPIOF,
+       RICOH619_INT_IR_CHGCTR, //RICOH619_INT_MON_CHGCTR,
+       RICOH619_INT_IR_CHGSTS1, //RICOH619_INT_MON_CHGSTS1,
+       RICOH619_INT_IR_CHGSTS2, //RICOH619_INT_MON_CHGSTS2,
+       RICOH619_INT_IR_CHGERR, //RICOH619_INT_MON_CHGERR
+       RICOH619_INT_IR_CHGEXTIF //RICOH619_INT_MON_CHGEXTIF
+};
+
+static int irq_clr_add[] = {
+       RICOH619_INT_IR_SYS,
+       RICOH619_INT_IR_DCDC,
+       RICOH619_INT_IR_RTC,
+       RICOH619_INT_IR_ADCL,
+       RICOH619_INT_IR_ADCH,
+       RICOH619_INT_IR_ADCEND,
+       RICOH619_INT_IR_GPIOR,
+       RICOH619_INT_IR_GPIOF,
+       RICOH619_INT_IR_CHGCTR,
+       RICOH619_INT_IR_CHGSTS1,
+       RICOH619_INT_IR_CHGSTS2,
+       RICOH619_INT_IR_CHGERR,
+       RICOH619_INT_IR_CHGEXTIF
+};
+
+static int main_int_type[] = {
+       SYS_INT,
+       DCDC_INT,
+       RTC_INT,
+       ADC_INT,
+       ADC_INT,
+       ADC_INT,
+       GPIO_INT,
+       GPIO_INT,
+       CHG_INT,
+       CHG_INT,
+       CHG_INT,
+       CHG_INT,
+       CHG_INT,
+};
+
+struct ricoh619_irq_data {
+       u8      int_type;
+       u8      master_bit;
+       u8      int_en_bit;
+       u8      mask_reg_index;
+       int     grp_index;
+};
+
+#define RICOH619_IRQ(_int_type, _master_bit, _grp_index, _int_bit, _mask_ind) \
+       {                                               \
+               .int_type       = _int_type,            \
+               .master_bit     = _master_bit,          \
+               .grp_index      = _grp_index,           \
+               .int_en_bit     = _int_bit,             \
+               .mask_reg_index = _mask_ind,            \
+       }
+
+static const struct ricoh619_irq_data ricoh619_irqs[RICOH619_NR_IRQS] = {
+       [RICOH619_IRQ_POWER_ON]         = RICOH619_IRQ(SYS_INT,  0, 0, 0, 0),
+       [RICOH619_IRQ_EXTIN]            = RICOH619_IRQ(SYS_INT,  0, 1, 1, 0),
+       [RICOH619_IRQ_PRE_VINDT]        = RICOH619_IRQ(SYS_INT,  0, 2, 2, 0),
+       [RICOH619_IRQ_PREOT]            = RICOH619_IRQ(SYS_INT,  0, 3, 3, 0),
+       [RICOH619_IRQ_POWER_OFF]        = RICOH619_IRQ(SYS_INT,  0, 4, 4, 0),
+       [RICOH619_IRQ_NOE_OFF]          = RICOH619_IRQ(SYS_INT,  0, 5, 5, 0),
+       [RICOH619_IRQ_WD]               = RICOH619_IRQ(SYS_INT,  0, 6, 6, 0),
+
+       [RICOH619_IRQ_DC1LIM]           = RICOH619_IRQ(DCDC_INT, 1, 0, 0, 1),
+       [RICOH619_IRQ_DC2LIM]           = RICOH619_IRQ(DCDC_INT, 1, 1, 1, 1),
+       [RICOH619_IRQ_DC3LIM]           = RICOH619_IRQ(DCDC_INT, 1, 2, 2, 1),
+       [RICOH619_IRQ_DC4LIM]           = RICOH619_IRQ(DCDC_INT, 1, 3, 3, 1),
+       [RICOH619_IRQ_DC5LIM]           = RICOH619_IRQ(DCDC_INT, 1, 4, 4, 1),
+       
+       [RICOH619_IRQ_CTC]              = RICOH619_IRQ(RTC_INT,  2, 0, 0, 2),
+       [RICOH619_IRQ_DALE]             = RICOH619_IRQ(RTC_INT,  2, 1, 6, 2),
+
+       [RICOH619_IRQ_ILIMLIR]          = RICOH619_IRQ(ADC_INT,  3, 0, 0, 3),
+       [RICOH619_IRQ_VBATLIR]          = RICOH619_IRQ(ADC_INT,  3, 1, 1, 3),
+       [RICOH619_IRQ_VADPLIR]          = RICOH619_IRQ(ADC_INT,  3, 2, 2, 3),
+       [RICOH619_IRQ_VUSBLIR]          = RICOH619_IRQ(ADC_INT,  3, 3, 3, 3),
+       [RICOH619_IRQ_VSYSLIR]          = RICOH619_IRQ(ADC_INT,  3, 4, 4, 3),
+       [RICOH619_IRQ_VTHMLIR]          = RICOH619_IRQ(ADC_INT,  3, 5, 5, 3),
+       [RICOH619_IRQ_AIN1LIR]          = RICOH619_IRQ(ADC_INT,  3, 6, 6, 3),
+       [RICOH619_IRQ_AIN0LIR]          = RICOH619_IRQ(ADC_INT,  3, 7, 7, 3),
+       
+       [RICOH619_IRQ_ILIMHIR]          = RICOH619_IRQ(ADC_INT,  3, 8, 0, 4),
+       [RICOH619_IRQ_VBATHIR]          = RICOH619_IRQ(ADC_INT,  3, 9, 1, 4),
+       [RICOH619_IRQ_VADPHIR]          = RICOH619_IRQ(ADC_INT,  3, 10, 2, 4),
+       [RICOH619_IRQ_VUSBHIR]          = RICOH619_IRQ(ADC_INT,  3, 11, 3, 4),
+       [RICOH619_IRQ_VSYSHIR]          = RICOH619_IRQ(ADC_INT,  3, 12, 4, 4),
+       [RICOH619_IRQ_VTHMHIR]          = RICOH619_IRQ(ADC_INT,  3, 13, 5, 4),
+       [RICOH619_IRQ_AIN1HIR]          = RICOH619_IRQ(ADC_INT,  3, 14, 6, 4),
+       [RICOH619_IRQ_AIN0HIR]          = RICOH619_IRQ(ADC_INT,  3, 15, 7, 4),
+
+       [RICOH619_IRQ_ADC_ENDIR]        = RICOH619_IRQ(ADC_INT,  3, 16, 0, 5),
+
+       [RICOH619_IRQ_GPIO0]            = RICOH619_IRQ(GPIO_INT, 4, 0, 0, 6),
+       [RICOH619_IRQ_GPIO1]            = RICOH619_IRQ(GPIO_INT, 4, 1, 1, 6),
+       [RICOH619_IRQ_GPIO2]            = RICOH619_IRQ(GPIO_INT, 4, 2, 2, 6),
+       [RICOH619_IRQ_GPIO3]            = RICOH619_IRQ(GPIO_INT, 4, 3, 3, 6),
+       [RICOH619_IRQ_GPIO4]            = RICOH619_IRQ(GPIO_INT, 4, 4, 4, 6),
+
+       [RICOH619_IRQ_FVADPDETSINT]     = RICOH619_IRQ(CHG_INT, 6, 0, 0, 8),
+       [RICOH619_IRQ_FVUSBDETSINT]     = RICOH619_IRQ(CHG_INT, 6, 1, 1, 8),
+       [RICOH619_IRQ_FVADPLVSINT]      = RICOH619_IRQ(CHG_INT, 6, 2, 2, 8),
+       [RICOH619_IRQ_FVUSBLVSINT]      = RICOH619_IRQ(CHG_INT, 6, 3, 3, 8),
+       [RICOH619_IRQ_FWVADPSINT]       = RICOH619_IRQ(CHG_INT, 6, 4, 4, 8),
+       [RICOH619_IRQ_FWVUSBSINT]       = RICOH619_IRQ(CHG_INT, 6, 5, 5, 8),
+
+       [RICOH619_IRQ_FONCHGINT]        = RICOH619_IRQ(CHG_INT, 6, 6, 0, 9),
+       [RICOH619_IRQ_FCHGCMPINT]       = RICOH619_IRQ(CHG_INT, 6, 7, 1, 9),
+       [RICOH619_IRQ_FBATOPENINT]      = RICOH619_IRQ(CHG_INT, 6, 8, 2, 9),
+       [RICOH619_IRQ_FSLPMODEINT]      = RICOH619_IRQ(CHG_INT, 6, 9, 3, 9),
+       [RICOH619_IRQ_FBTEMPJTA1INT]    = RICOH619_IRQ(CHG_INT, 6, 10, 4, 9),
+       [RICOH619_IRQ_FBTEMPJTA2INT]    = RICOH619_IRQ(CHG_INT, 6, 11, 5, 9),
+       [RICOH619_IRQ_FBTEMPJTA3INT]    = RICOH619_IRQ(CHG_INT, 6, 12, 6, 9),
+       [RICOH619_IRQ_FBTEMPJTA4INT]    = RICOH619_IRQ(CHG_INT, 6, 13, 7, 9),
+
+       [RICOH619_IRQ_FCURTERMINT]      = RICOH619_IRQ(CHG_INT, 6, 14, 0, 10),
+       [RICOH619_IRQ_FVOLTERMINT]      = RICOH619_IRQ(CHG_INT, 6, 15, 1, 10),
+       [RICOH619_IRQ_FICRVSINT]        = RICOH619_IRQ(CHG_INT, 6, 16, 2, 10),
+       [RICOH619_IRQ_FPOOR_CHGCURINT]  = RICOH619_IRQ(CHG_INT, 6, 17, 3, 10),
+       [RICOH619_IRQ_FOSCFDETINT1]     = RICOH619_IRQ(CHG_INT, 6, 18, 4, 10),
+       [RICOH619_IRQ_FOSCFDETINT2]     = RICOH619_IRQ(CHG_INT, 6, 19, 5, 10),
+       [RICOH619_IRQ_FOSCFDETINT3]     = RICOH619_IRQ(CHG_INT, 6, 20, 6, 10),
+       [RICOH619_IRQ_FOSCMDETINT]      = RICOH619_IRQ(CHG_INT, 6, 21, 7, 10),
+
+       [RICOH619_IRQ_FDIEOFFINT]       = RICOH619_IRQ(CHG_INT, 6, 22, 0, 11),
+       [RICOH619_IRQ_FDIEERRINT]       = RICOH619_IRQ(CHG_INT, 6, 23, 1, 11),
+       [RICOH619_IRQ_FBTEMPERRINT]     = RICOH619_IRQ(CHG_INT, 6, 24, 2, 11),
+       [RICOH619_IRQ_FVBATOVINT]       = RICOH619_IRQ(CHG_INT, 6, 25, 3, 11),
+       [RICOH619_IRQ_FTTIMOVINT]       = RICOH619_IRQ(CHG_INT, 6, 26, 4, 11),
+       [RICOH619_IRQ_FRTIMOVINT]       = RICOH619_IRQ(CHG_INT, 6, 27, 5, 11),
+       [RICOH619_IRQ_FVADPOVSINT]      = RICOH619_IRQ(CHG_INT, 6, 28, 6, 11),
+       [RICOH619_IRQ_FVUSBOVSINT]      = RICOH619_IRQ(CHG_INT, 6, 29, 7, 11),
+
+       [RICOH619_IRQ_FGCDET]           = RICOH619_IRQ(CHG_INT, 6, 30, 0, 12),
+       [RICOH619_IRQ_FPCDET]           = RICOH619_IRQ(CHG_INT, 6, 31, 1, 12),
+       [RICOH619_IRQ_FWARN_ADP]        = RICOH619_IRQ(CHG_INT, 6, 32, 3, 12),
+
+};
+
+static void ricoh619_irq_lock(struct irq_data *irq_data)
+{
+       struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+
+       mutex_lock(&ricoh619->irq_lock);
+}
+
+static void ricoh619_irq_unmask(struct irq_data *irq_data)
+{
+       struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - ricoh619->irq_base;
+       const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq];
+
+       ricoh619->group_irq_en[data->master_bit] |= (1 << data->grp_index);
+       if (ricoh619->group_irq_en[data->master_bit])
+               ricoh619->intc_inten_reg |= 1 << data->master_bit;
+
+       if (data->master_bit == 6)      /* if Charger */
+               ricoh619->irq_en_reg[data->mask_reg_index]
+                                               &= ~(1 << data->int_en_bit);
+       else
+               ricoh619->irq_en_reg[data->mask_reg_index]
+                                               |= 1 << data->int_en_bit;
+}
+
+static void ricoh619_irq_mask(struct irq_data *irq_data)
+{
+       struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - ricoh619->irq_base;
+       const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq];
+
+       ricoh619->group_irq_en[data->master_bit] &= ~(1 << data->grp_index);
+       if (!ricoh619->group_irq_en[data->master_bit])
+               ricoh619->intc_inten_reg &= ~(1 << data->master_bit);
+
+       if (data->master_bit == 6)      /* if Charger */
+               ricoh619->irq_en_reg[data->mask_reg_index]
+                                               |= 1 << data->int_en_bit;
+       else
+               ricoh619->irq_en_reg[data->mask_reg_index]
+                                               &= ~(1 << data->int_en_bit);
+}
+
+static void ricoh619_irq_sync_unlock(struct irq_data *irq_data)
+{
+       struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ricoh619->gpedge_reg); i++) {
+               if (ricoh619->gpedge_reg[i] != ricoh619->gpedge_cache[i]) {
+                       if (!WARN_ON(ricoh619_write(ricoh619->dev,
+                                                   gpedge_add[i],
+                                                   ricoh619->gpedge_reg[i])))
+                               ricoh619->gpedge_cache[i] =
+                                               ricoh619->gpedge_reg[i];
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ricoh619->irq_en_reg); i++) {
+               if (ricoh619->irq_en_reg[i] != ricoh619->irq_en_cache[i]) {
+                       if (!WARN_ON(ricoh619_write(ricoh619->dev,
+                                                   irq_en_add[i],
+                                                   ricoh619->irq_en_reg[i])))
+                               ricoh619->irq_en_cache[i] =
+                                               ricoh619->irq_en_reg[i];
+               }
+       }
+
+       if (ricoh619->intc_inten_reg != ricoh619->intc_inten_cache) {
+               if (!WARN_ON(ricoh619_write(ricoh619->dev,
+                               RICOH619_INTC_INTEN, ricoh619->intc_inten_reg)))
+                       ricoh619->intc_inten_cache = ricoh619->intc_inten_reg;
+       }
+
+       mutex_unlock(&ricoh619->irq_lock);
+}
+
+static int ricoh619_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+       struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - ricoh619->irq_base;
+       const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq];
+       int val = 0;
+       int gpedge_index;
+       int gpedge_bit_pos;
+
+       if (data->int_type & GPIO_INT) {
+               gpedge_index = data->int_en_bit / 4;
+               gpedge_bit_pos = data->int_en_bit % 4;
+
+               if (type & IRQ_TYPE_EDGE_FALLING)
+                       val |= 0x2;
+
+               if (type & IRQ_TYPE_EDGE_RISING)
+                       val |= 0x1;
+
+               ricoh619->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+               ricoh619->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+               ricoh619_irq_unmask(irq_data);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ricoh619_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+       struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+       return irq_set_irq_wake(ricoh619->chip_irq, on);        //i2c->irq
+}
+#else
+#define ricoh619_irq_set_wake NULL
+#endif
+
+static irqreturn_t ricoh619_irq(int irq, void *data)
+{
+       struct ricoh619 *ricoh619 = data;
+       u8 int_sts[MAX_INTERRUPT_MASKS];
+       u8 master_int;
+       int i;
+       int ret;
+       unsigned int rtc_int_sts = 0;
+
+       /* Clear the status */
+       for (i = 0; i < MAX_INTERRUPT_MASKS; i++)
+               int_sts[i] = 0;
+
+       ret = ricoh619_read(ricoh619->dev, RICOH619_INTC_INTMON,
+                                               &master_int);
+//     printk("PMU1: %s: master_int=0x%x\n", __func__, master_int);
+       if (ret < 0) {
+               dev_err(ricoh619->dev, "Error in reading reg 0x%02x "
+                       "error: %d\n", RICOH619_INTC_INTMON, ret);
+               return IRQ_HANDLED;
+       }
+
+/* Mask Charger Interrupt */
+       if((CHG_INT | ADC_INT) & master_int){
+               for (i=8; i < MAX_INTERRUPT_MASKS; i++) {
+                       ret = ricoh619_write(ricoh619->dev,
+                                                       irq_en_add[i], 0xff);
+                               if (ret < 0) {
+                                       dev_err(ricoh619->dev,
+                                               "Error in write reg 0x%02x "
+                                                       "error: %d\n",
+                                                       irq_en_add[i], ret);
+                               }
+               }
+               //Disable ADC interrupt
+               for (i=3; i < 6; i++) {
+                       ret = ricoh619_write(ricoh619->dev, irq_en_add[i], 0x0);
+                       if (ret < 0) {
+                               dev_err(ricoh619->dev, "Error in write reg 0x%02x "
+                                               "error: %d\n", irq_en_add[i],
+                                                                       ret);
+                       }
+               }
+       }
+       
+       for (i = 0; i < MAX_INTERRUPT_MASKS; ++i) {
+               /* Even if INTC_INTMON register = 1, INT signal might not output
+                because INTC_INTMON register indicates only interrupt facter level.
+                So remove the following procedure */
+//             if (!(master_int & main_int_type[i]))
+//                     continue;
+                       
+               ret = ricoh619_read(ricoh619->dev,
+                               irq_mon_add[i], &int_sts[i]);
+//             printk("PMU2: %s: int_sts[%d]=0x%x\n", __func__,i, int_sts[i]);
+               if (ret < 0) {
+                       dev_err(ricoh619->dev, "Error in reading reg 0x%02x "
+                               "error: %d\n", irq_mon_add[i], ret);
+                       int_sts[i] = 0;
+                       continue;
+               }
+               
+               if (main_int_type[i] & RTC_INT) {
+                       // Changes status bit position from RTCCNT2 to RTCCNT1 
+                       rtc_int_sts = 0;
+                       if (int_sts[i] & 0x1)
+                               rtc_int_sts |= BIT(6);
+                       if (int_sts[i] & 0x4)
+                               rtc_int_sts |= BIT(0);
+               }
+
+               ret = ricoh619_write(ricoh619->dev,
+                               irq_clr_add[i], ~int_sts[i]);
+               if (ret < 0) {
+                       dev_err(ricoh619->dev, "Error in reading reg 0x%02x "
+                               "error: %d\n", irq_clr_add[i], ret);
+               }
+               
+               if (main_int_type[i] & RTC_INT)
+                       int_sts[i] = rtc_int_sts;
+
+       }
+
+       /* Merge gpio interrupts  for rising and falling case*/
+       int_sts[6] |= int_sts[7];
+
+       /* Call interrupt handler if enabled */
+       for (i = 0; i < RICOH619_NR_IRQS; ++i) {
+               const struct ricoh619_irq_data *data = &ricoh619_irqs[i];
+               if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+                       (ricoh619->group_irq_en[data->master_bit] & 
+                                                       (1 << data->grp_index)))
+                       handle_nested_irq(ricoh619->irq_base + i);
+       }
+
+//     printk(KERN_INFO "PMU: %s: out\n", __func__);
+       return IRQ_HANDLED;
+}
+
+static struct irq_chip ricoh619_irq_chip = {
+       .name = "ricoh619",
+       .irq_mask = ricoh619_irq_mask,
+       .irq_unmask = ricoh619_irq_unmask,
+       .irq_bus_lock = ricoh619_irq_lock,
+       .irq_bus_sync_unlock = ricoh619_irq_sync_unlock,
+       .irq_set_type = ricoh619_irq_set_type,
+       .irq_set_wake = ricoh619_irq_set_wake,
+};
+
+int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq,
+                               int irq_base)
+{
+       int i, ret;
+
+       if (!irq_base) {
+               dev_warn(ricoh619->dev, "No interrupt support on IRQ base\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&ricoh619->irq_lock);
+
+       /* Initialize all locals to 0 */
+       for (i = 0; i < 8; i++) {
+               ricoh619->irq_en_cache[i] = 0;
+               ricoh619->irq_en_reg[i] = 0;
+       }
+       // Charger Mask register must be set to 1 for masking Int output.
+       for (i = 8; i < MAX_INTERRUPT_MASKS; i++) {
+               ricoh619->irq_en_cache[i] = 0xff;
+               ricoh619->irq_en_reg[i] = 0xff;
+       }
+       
+       ricoh619->intc_inten_cache = 0;
+       ricoh619->intc_inten_reg = 0;
+       for (i = 0; i < MAX_GPEDGE_REG; i++) {
+               ricoh619->gpedge_cache[i] = 0;
+               ricoh619->gpedge_reg[i] = 0;
+       }
+
+       /* Initailize all int register to 0 */
+       for (i = 0; i < MAX_INTERRUPT_MASKS; i++)  {
+               ret = ricoh619_write(ricoh619->dev,
+                               irq_en_add[i],
+                               ricoh619->irq_en_reg[i]);
+               if (ret < 0)
+                       dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+                               "error: %d\n", irq_en_add[i], ret);
+       }
+
+       for (i = 0; i < MAX_GPEDGE_REG; i++)  {
+               ret = ricoh619_write(ricoh619->dev,
+                               gpedge_add[i],
+                               ricoh619->gpedge_reg[i]);
+               if (ret < 0)
+                       dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+                               "error: %d\n", gpedge_add[i], ret);
+       }
+
+       ret = ricoh619_write(ricoh619->dev, RICOH619_INTC_INTEN, 0x0);
+       if (ret < 0)
+               dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+                               "error: %d\n", RICOH619_INTC_INTEN, ret);
+
+       /* Clear all interrupts in case they woke up active. */
+       for (i = 0; i < MAX_INTERRUPT_MASKS; i++)  {
+               ret = ricoh619_write(ricoh619->dev,
+                                       irq_clr_add[i], 0);
+               if (ret < 0)
+                       dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+                               "error: %d\n", irq_clr_add[i], ret);
+       }
+
+       ricoh619->irq_base = irq_base;
+       ricoh619->chip_irq = irq;
+
+       for (i = 0; i < RICOH619_NR_IRQS; i++) {
+               int __irq = i + ricoh619->irq_base;
+               irq_set_chip_data(__irq, ricoh619);
+               irq_set_chip_and_handler(__irq, &ricoh619_irq_chip,
+                                        handle_simple_irq);
+               irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+               set_irq_flags(__irq, IRQF_VALID);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, ricoh619_irq,
+                       IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED|IRQF_ONESHOT,
+                                                  "ricoh619", ricoh619);
+       if (ret < 0)
+               dev_err(ricoh619->dev, "Error in registering interrupt "
+                               "error: %d\n", ret);
+/*
+       if (!ret) {
+               device_init_wakeup(ricoh619->dev, 1);
+               enable_irq_wake(irq);
+       }
+*/
+
+       return ret;
+}
+
+int ricoh619_irq_exit(struct ricoh619 *ricoh619)
+{
+       if (ricoh619->chip_irq)
+               free_irq(ricoh619->chip_irq, ricoh619);
+       return 0;
+}
+
diff --git a/drivers/mfd/ricoh619.c b/drivers/mfd/ricoh619.c
new file mode 100644 (file)
index 0000000..70a1ef0
--- /dev/null
@@ -0,0 +1,852 @@
+/* 
+ * driver/mfd/ricoh619.c
+ *
+ * Core driver implementation to access RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *     Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+/*#define DEBUG                        1*/
+/*#define VERBOSE_DEBUG                1*/
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ricoh619.h>
+
+
+struct ricoh619 *g_ricoh619;
+struct sleep_control_data {
+       u8 reg_add;
+};
+
+#define SLEEP_INIT(_id, _reg)          \
+       [RICOH619_DS_##_id] = {.reg_add = _reg}
+
+static struct sleep_control_data sleep_data[] = {
+       SLEEP_INIT(DC1, 0x16),
+       SLEEP_INIT(DC2, 0x17),
+       SLEEP_INIT(DC3, 0x18),
+       SLEEP_INIT(DC4, 0x19),
+       SLEEP_INIT(DC5, 0x1A),
+       SLEEP_INIT(LDO1, 0x1B),
+       SLEEP_INIT(LDO2, 0x1C),
+       SLEEP_INIT(LDO3, 0x1D),
+       SLEEP_INIT(LDO4, 0x1E),
+       SLEEP_INIT(LDO5, 0x1F),
+       SLEEP_INIT(LDO6, 0x20),
+       SLEEP_INIT(LDO7, 0x21),
+       SLEEP_INIT(LDO8, 0x22),
+       SLEEP_INIT(LDO9, 0x23),
+       SLEEP_INIT(LDO10, 0x24),
+       SLEEP_INIT(PSO0, 0x25),
+       SLEEP_INIT(PSO1, 0x26),
+       SLEEP_INIT(PSO2, 0x27),
+       SLEEP_INIT(PSO3, 0x28),
+       SLEEP_INIT(PSO4, 0x29),
+       SLEEP_INIT(LDORTC1, 0x2A),
+};
+
+static inline int __ricoh619_read(struct i2c_client *client,
+                                 u8 reg, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+               return ret;
+       }
+
+       *val = (uint8_t)ret;
+       dev_dbg(&client->dev, "ricoh619: reg read  reg=%x, val=%x\n",
+                               reg, *val);
+       return 0;
+}
+
+static inline int __ricoh619_bulk_reads(struct i2c_client *client, u8 reg,
+                               int len, uint8_t *val)
+{
+       int ret;
+       int i;
+
+       ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
+               return ret;
+       }
+       for (i = 0; i < len; ++i) {
+               dev_dbg(&client->dev, "ricoh619: reg read  reg=%x, val=%x\n",
+                               reg + i, *(val + i));
+       }
+       return 0;
+}
+
+static inline int __ricoh619_write(struct i2c_client *client,
+                                u8 reg, uint8_t val)
+{
+       int ret;
+
+       dev_dbg(&client->dev, "ricoh619: reg write  reg=%x, val=%x\n",
+                               reg, val);
+       ret = i2c_smbus_write_byte_data(client, reg, val);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
+                               val, reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline int __ricoh619_bulk_writes(struct i2c_client *client, u8 reg,
+                                 int len, uint8_t *val)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < len; ++i) {
+               dev_dbg(&client->dev, "ricoh619: reg write  reg=%x, val=%x\n",
+                               reg + i, *(val + i));
+       }
+
+       ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline int set_bank_ricoh619(struct device *dev, int bank)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret;
+
+       if (bank != (bank & 1))
+               return -EINVAL;
+       if (bank == ricoh619->bank_num)
+               return 0;
+       ret = __ricoh619_write(to_i2c_client(dev), RICOH619_REG_BANKSEL, bank);
+       if (!ret)
+               ricoh619->bank_num = bank;
+
+       return ret;
+}
+
+int ricoh619_write(struct device *dev, u8 reg, uint8_t val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if( !ret )
+               ret = __ricoh619_write(to_i2c_client(dev), reg, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_write);
+
+int ricoh619_write_bank1(struct device *dev, u8 reg, uint8_t val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 1);
+       if( !ret ) 
+               ret = __ricoh619_write(to_i2c_client(dev), reg, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_write_bank1);
+
+int ricoh619_bulk_writes(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if( !ret )
+               ret = __ricoh619_bulk_writes(to_i2c_client(dev), reg, len, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_writes);
+
+int ricoh619_bulk_writes_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 1);
+       if( !ret ) 
+               ret = __ricoh619_bulk_writes(to_i2c_client(dev), reg, len, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_writes_bank1);
+
+int ricoh619_read(struct device *dev, u8 reg, uint8_t *val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if( !ret )
+               ret = __ricoh619_read(to_i2c_client(dev), reg, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_read);
+
+int ricoh619_read_bank1(struct device *dev, u8 reg, uint8_t *val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 1);
+       if( !ret )
+               ret =  __ricoh619_read(to_i2c_client(dev), reg, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(ricoh619_read_bank1);
+
+int ricoh619_bulk_reads(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if( !ret ) 
+               ret = __ricoh619_bulk_reads(to_i2c_client(dev), reg, len, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_reads);
+
+int ricoh619_bulk_reads_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 1);
+       if( !ret ) 
+               ret = __ricoh619_bulk_reads(to_i2c_client(dev), reg, len, val);
+       mutex_unlock(&ricoh619->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_reads_bank1);
+
+int ricoh619_set_bits(struct device *dev, u8 reg, uint8_t bit_mask)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if (!ret) {
+               ret = __ricoh619_read(to_i2c_client(dev), reg, &reg_val);
+               if (ret)
+                       goto out;
+
+               if ((reg_val & bit_mask) != bit_mask) {
+                       reg_val |= bit_mask;
+                       ret = __ricoh619_write(to_i2c_client(dev), reg,
+                                                                reg_val);
+               }
+       }
+out:
+       mutex_unlock(&ricoh619->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_set_bits);
+
+int ricoh619_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if( !ret ){
+               ret = __ricoh619_read(to_i2c_client(dev), reg, &reg_val);
+               if (ret)
+                       goto out;
+
+               if (reg_val & bit_mask) {
+                       reg_val &= ~bit_mask;
+                       ret = __ricoh619_write(to_i2c_client(dev), reg,
+                                                                reg_val);
+               }
+       }
+out:
+       mutex_unlock(&ricoh619->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_clr_bits);
+
+int ricoh619_update(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 0);
+       if( !ret ){
+               ret = __ricoh619_read(ricoh619->client, reg, &reg_val);
+               if (ret)
+                       goto out;
+
+               if ((reg_val & mask) != val) {
+                       reg_val = (reg_val & ~mask) | (val & mask);
+                       ret = __ricoh619_write(ricoh619->client, reg, reg_val);
+               }
+       }
+out:
+       mutex_unlock(&ricoh619->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_update);
+
+int ricoh619_update_bank1(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
+{
+       struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&ricoh619->io_lock);
+       ret = set_bank_ricoh619(dev, 1);
+       if( !ret ){
+               ret = __ricoh619_read(ricoh619->client, reg, &reg_val);
+               if (ret)
+                       goto out;
+
+               if ((reg_val & mask) != val) {
+                       reg_val = (reg_val & ~mask) | (val & mask);
+                       ret = __ricoh619_write(ricoh619->client, reg, reg_val);
+               }
+       }
+out:
+       mutex_unlock(&ricoh619->io_lock);
+       return ret;
+}
+
+static struct i2c_client *ricoh619_i2c_client;
+int ricoh619_power_off(void)
+{
+       int ret;
+       uint8_t val;
+       int err = -1;
+       struct ricoh619 *ricoh619 = g_ricoh619;
+
+       val = g_soc;
+       val &= 0x7f;
+       ret = ricoh619_write(ricoh619->dev, RICOH619_PSWR, val);
+       if (ret < 0)
+               dev_err(ricoh619->dev, "Error in writing PSWR_REG\n");
+
+       if (g_fg_on_mode == 0) {
+               ret = ricoh619_clr_bits(ricoh619->dev,
+                                        RICOH619_FG_CTRL, 0x01);
+               if (ret < 0)
+                       dev_err(ricoh619->dev, "Error in writing FG_CTRL\n");
+       }
+
+       if (!ricoh619_i2c_client)
+               return -EINVAL;
+//__ricoh618_write(ricoh618_i2c_client, RICOH618_PWR_REP_CNT, 0x0); //Not repeat power ON after power off(Power Off/N_OE)
+//     __ricoh618_write(ricoh618_i2c_client, RICOH618_PWR_SLP_CNT, 0x1); //Power OFF
+       ret = ricoh619_clr_bits(ricoh619->dev,RICOH619_PWR_REP_CNT,(0x1<<0));//Not repeat power ON after power off(Power Off/N_OE)
+       ret = ricoh619_set_bits(ricoh619->dev, RICOH619_PWR_SLP_CNT,(0x1<<0));//Power OFF
+       if (ret < 0) {
+               printk("ricoh619 power off error!\n");
+               return err;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ricoh619_power_off);
+
+static int ricoh619_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+       uint8_t val;
+       int ret;
+
+       ret = ricoh619_read(ricoh619->dev, RICOH619_GPIO_MON_IOIN, &val);
+       if (ret < 0)
+               return ret;
+
+       return ((val & (0x1 << offset)) != 0);
+}
+
+static void ricoh619_gpio_set(struct gpio_chip *gc, unsigned offset,
+                       int value)
+{
+       struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+       if (value)
+               ricoh619_set_bits(ricoh619->dev, RICOH619_GPIO_IOOUT,
+                                               1 << offset);
+       else
+               ricoh619_clr_bits(ricoh619->dev, RICOH619_GPIO_IOOUT,
+                                               1 << offset);
+}
+
+static int ricoh619_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+
+       return ricoh619_clr_bits(ricoh619->dev, RICOH619_GPIO_IOSEL,
+                                               1 << offset);
+}
+
+static int ricoh619_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+
+       ricoh619_gpio_set(gc, offset, value);
+       return ricoh619_set_bits(ricoh619->dev, RICOH619_GPIO_IOSEL,
+                                               1 << offset);
+}
+
+static int ricoh619_gpio_to_irq(struct gpio_chip *gc, unsigned off)
+{
+       struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+
+       if ((off >= 0) && (off < 8))
+               return ricoh619->irq_base + RICOH619_IRQ_GPIO0 + off;
+
+       return -EIO;
+}
+
+
+static void __devinit ricoh619_gpio_init(struct ricoh619 *ricoh619,
+       struct ricoh619_platform_data *pdata)
+{
+       int ret;
+       int i;
+       struct ricoh619_gpio_init_data *ginit;
+
+       if (pdata->gpio_base  <= 0)
+               return;
+
+       for (i = 0; i < pdata->num_gpioinit_data; ++i) {
+               ginit = &pdata->gpio_init_data[i];
+
+               if (!ginit->init_apply)
+                       continue;
+
+               if (ginit->output_mode_en) {
+                       /* GPIO output mode */
+                       if (ginit->output_val)
+                               /* output H */
+                               ret = ricoh619_set_bits(ricoh619->dev,
+                                       RICOH619_GPIO_IOOUT, 1 << i);
+                       else
+                               /* output L */
+                               ret = ricoh619_clr_bits(ricoh619->dev,
+                                       RICOH619_GPIO_IOOUT, 1 << i);
+                       if (!ret)
+                               ret = ricoh619_set_bits(ricoh619->dev,
+                                       RICOH619_GPIO_IOSEL, 1 << i);
+               } else
+                       /* GPIO input mode */
+                       ret = ricoh619_clr_bits(ricoh619->dev,
+                                       RICOH619_GPIO_IOSEL, 1 << i);
+
+               /* if LED function enabled in OTP */
+               if (ginit->led_mode) {
+                       /* LED Mode 1 */
+                       if (i == 0)     /* GP0 */
+                               ret = ricoh619_set_bits(ricoh619->dev,
+                                        RICOH619_GPIO_LED_FUNC,
+                                        0x04 | (ginit->led_func & 0x03));
+                       if (i == 1)     /* GP1 */
+                               ret = ricoh619_set_bits(ricoh619->dev,
+                                        RICOH619_GPIO_LED_FUNC,
+                                        0x40 | (ginit->led_func & 0x03) << 4);
+
+               }
+
+
+               if (ret < 0)
+                       dev_err(ricoh619->dev, "Gpio %d init "
+                               "dir configuration failed: %d\n", i, ret);
+
+       }
+
+       ricoh619->gpio_chip.owner               = THIS_MODULE;
+       ricoh619->gpio_chip.label               = ricoh619->client->name;
+       ricoh619->gpio_chip.dev                 = ricoh619->dev;
+       ricoh619->gpio_chip.base                = pdata->gpio_base;
+       ricoh619->gpio_chip.ngpio               = RICOH619_NR_GPIO;
+       ricoh619->gpio_chip.can_sleep   = 1;
+
+       ricoh619->gpio_chip.direction_input     = ricoh619_gpio_input;
+       ricoh619->gpio_chip.direction_output    = ricoh619_gpio_output;
+       ricoh619->gpio_chip.set                 = ricoh619_gpio_set;
+       ricoh619->gpio_chip.get                 = ricoh619_gpio_get;
+       ricoh619->gpio_chip.to_irq              = ricoh619_gpio_to_irq;
+
+       ret = gpiochip_add(&ricoh619->gpio_chip);
+       if (ret)
+               dev_warn(ricoh619->dev, "GPIO registration failed: %d\n", ret);
+}
+
+static int ricoh619_remove_subdev(struct device *dev, void *unused)
+{
+       platform_device_unregister(to_platform_device(dev));
+       return 0;
+}
+
+static int ricoh619_remove_subdevs(struct ricoh619 *ricoh619)
+{
+       return device_for_each_child(ricoh619->dev, NULL,
+                                    ricoh619_remove_subdev);
+}
+
+static int __devinit ricoh619_add_subdevs(struct ricoh619 *ricoh619,
+                               struct ricoh619_platform_data *pdata)
+{
+       struct ricoh619_subdev_info *subdev;
+       struct platform_device *pdev;
+       int i, ret = 0;
+
+       for (i = 0; i < pdata->num_subdevs; i++) {
+               subdev = &pdata->subdevs[i];
+
+               pdev = platform_device_alloc(subdev->name, subdev->id);
+
+               pdev->dev.parent = ricoh619->dev;
+               pdev->dev.platform_data = subdev->platform_data;
+
+               ret = platform_device_add(pdev);
+               if (ret)
+                       goto failed;
+       }
+       return 0;
+
+failed:
+       ricoh619_remove_subdevs(ricoh619);
+       return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+static void print_regs(const char *header, struct seq_file *s,
+               struct i2c_client *client, int start_offset,
+               int end_offset)
+{
+       uint8_t reg_val;
+       int i;
+       int ret;
+
+       seq_printf(s, "%s\n", header);
+       for (i = start_offset; i <= end_offset; ++i) {
+               ret = __ricoh619_read(client, i, &reg_val);
+               if (ret >= 0)
+                       seq_printf(s, "Reg 0x%02x Value 0x%02x\n", i, reg_val);
+       }
+       seq_printf(s, "------------------\n");
+}
+
+static int dbg_ricoh_show(struct seq_file *s, void *unused)
+{
+       struct ricoh619 *ricoh = s->private;
+       struct i2c_client *client = ricoh->client;
+
+       seq_printf(s, "RICOH619 Registers\n");
+       seq_printf(s, "------------------\n");
+
+       print_regs("System Regs",               s, client, 0x0, 0x05);
+       print_regs("Power Control Regs",        s, client, 0x07, 0x2B);
+       print_regs("DCDC  Regs",                s, client, 0x2C, 0x43);
+       print_regs("LDO   Regs",                s, client, 0x44, 0x61);
+       print_regs("ADC   Regs",                s, client, 0x64, 0x8F);
+       print_regs("GPIO  Regs",                s, client, 0x90, 0x98);
+       print_regs("INTC  Regs",                s, client, 0x9C, 0x9E);
+       print_regs("RTC   Regs",                s, client, 0xA0, 0xAF);
+       print_regs("OPT   Regs",                s, client, 0xB0, 0xB1);
+       print_regs("CHG   Regs",                s, client, 0xB2, 0xDF);
+       print_regs("FUEL  Regs",                s, client, 0xE0, 0xFC);
+       return 0;
+}
+
+static int dbg_ricoh_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dbg_ricoh_show, inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+       .open           = dbg_ricoh_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+static void __init ricoh619_debuginit(struct ricoh619 *ricoh)
+{
+       (void)debugfs_create_file("ricoh619", S_IRUGO, NULL,
+                       ricoh, &debug_fops);
+}
+#else
+static void print_regs(const char *header, struct i2c_client *client,
+               int start_offset, int end_offset)
+{
+       uint8_t reg_val;
+       int i;
+       int ret;
+
+       printk(KERN_INFO "%s\n", header);
+       for (i = start_offset; i <= end_offset; ++i) {
+               ret = __ricoh619_read(client, i, &reg_val);
+               if (ret >= 0)
+                       printk(KERN_INFO "Reg 0x%02x Value 0x%02x\n",
+                                                        i, reg_val);
+       }
+       printk(KERN_INFO "------------------\n");
+}
+static void __init ricoh619_debuginit(struct ricoh619 *ricoh)
+{
+       struct i2c_client *client = ricoh->client;
+
+       printk(KERN_INFO "RICOH619 Registers\n");
+       printk(KERN_INFO "------------------\n");
+
+       print_regs("System Regs",               client, 0x0, 0x05);
+       print_regs("Power Control Regs",        client, 0x07, 0x2B);
+       print_regs("DCDC  Regs",                client, 0x2C, 0x43);
+       print_regs("LDO   Regs",                client, 0x44, 0x5C);
+       print_regs("ADC   Regs",                client, 0x64, 0x8F);
+       print_regs("GPIO  Regs",                client, 0x90, 0x9B);
+       print_regs("INTC  Regs",                client, 0x9C, 0x9E);
+       print_regs("OPT   Regs",                client, 0xB0, 0xB1);
+       print_regs("CHG   Regs",                client, 0xB2, 0xDF);
+       print_regs("FUEL  Regs",                client, 0xE0, 0xFC);
+
+       return 0;
+}
+#endif
+
+static void __devinit ricoh619_noe_init(struct ricoh619 *ricoh)
+{
+       struct i2c_client *client = ricoh->client;
+       
+       __ricoh619_write(client, RICOH619_PWR_NOE_TIMSET, 0x0); //N_OE timer setting to 128mS
+       __ricoh619_write(client, RICOH619_PWR_REP_CNT, 0x1); //Repeat power ON after reset (Power Off/N_OE)
+}
+
+static int ricoh619_i2c_probe(struct i2c_client *client,
+                             const struct i2c_device_id *id)
+{
+       struct ricoh619 *ricoh619;
+       struct ricoh619_platform_data *pdata = client->dev.platform_data;
+       int ret;
+       uint8_t control;
+       printk(KERN_INFO "PMU: %s:\n", __func__);
+
+       ricoh619 = kzalloc(sizeof(struct ricoh619), GFP_KERNEL);
+       if (ricoh619 == NULL)
+               return -ENOMEM;
+
+       ricoh619->client = client;
+       ricoh619->dev = &client->dev;
+       i2c_set_clientdata(client, ricoh619);
+
+       mutex_init(&ricoh619->io_lock);
+
+       ret = ricoh619_read(ricoh619->dev, 0x36, &control);
+       if ((control < 0) || (control == 0xff)) {
+               printk(KERN_INFO "The device is not ricoh619\n");
+               return 0;
+       }
+       /***************set noe time 128ms**************/
+       ret = ricoh619_set_bits(ricoh619->dev,0x11,(0x1 <<3));
+       ret = ricoh619_clr_bits(ricoh619->dev,0x11,(0x7 <<0));
+       ret = ricoh619_clr_bits(ricoh619->dev,0x11,(0x1 <<3));
+       /**********************************************/
+
+       /***************set PKEY long press time 0sec*******/
+       ret = ricoh619_set_bits(ricoh619->dev,0x10,(0x1 <<7));
+       ret = ricoh619_clr_bits(ricoh619->dev,0x10,(0x1 <<3));
+       ret = ricoh619_clr_bits(ricoh619->dev,0x10,(0x1 <<7));
+       /**********************************************/
+
+       ricoh619->bank_num = 0;
+
+//     ret = pdata->init_port(client->irq); // For init PMIC_IRQ port
+       if (client->irq) {
+               ret = ricoh619_irq_init(ricoh619, client->irq, pdata->irq_base);
+               if (ret) {
+                       dev_err(&client->dev, "IRQ init failed: %d\n", ret);
+                       goto err_irq_init;
+               }
+       }
+       
+       ret = ricoh619_add_subdevs(ricoh619, pdata);
+       if (ret) {
+               dev_err(&client->dev, "add devices failed: %d\n", ret);
+               goto err_add_devs;
+       }
+       ricoh619_noe_init(ricoh619);
+       
+       g_ricoh619 = ricoh619;
+       if (pdata && pdata->pre_init) {
+               ret = pdata->pre_init(ricoh619);
+               if (ret != 0) {
+                       dev_err(ricoh619->dev, "pre_init() failed: %d\n", ret);
+                       goto err;
+               }
+       }
+
+       //ricoh619_gpio_init(ricoh619, pdata);
+
+       ricoh619_debuginit(ricoh619);
+
+       if (pdata && pdata->post_init) {
+               ret = pdata->post_init(ricoh619);
+               if (ret != 0) {
+                       dev_err(ricoh619->dev, "post_init() failed: %d\n", ret);
+                       goto err;
+               }
+       }
+
+       ricoh619_i2c_client = client;
+       return 0;
+err:
+       mfd_remove_devices(ricoh619->dev);
+       kfree(ricoh619);
+err_add_devs:
+       if (client->irq)
+               ricoh619_irq_exit(ricoh619);
+err_irq_init:
+       kfree(ricoh619);
+       return ret;
+}
+
+static int  __devexit ricoh619_i2c_remove(struct i2c_client *client)
+{
+       struct ricoh619 *ricoh619 = i2c_get_clientdata(client);
+
+       if (client->irq)
+               ricoh619_irq_exit(ricoh619);
+
+       ricoh619_remove_subdevs(ricoh619);
+       kfree(ricoh619);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ricoh619_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+       if (client->irq)
+               disable_irq(client->irq);
+       return 0;
+}
+
+int pwrkey_wakeup;
+static int ricoh619_i2c_resume(struct i2c_client *client)
+{
+       uint8_t reg_val;
+       int ret;
+
+       ret = __ricoh619_read(client, RICOH619_INT_IR_SYS, &reg_val);
+       if(reg_val & 0x01) { //If PWR_KEY wakeup
+//             printk("PMU: %s: PWR_KEY Wakeup\n",__func__);
+               pwrkey_wakeup = 1;
+               __ricoh619_write(client, RICOH619_INT_IR_SYS, 0x0); //Clear PWR_KEY IRQ
+       }
+
+       enable_irq(client->irq);
+       return 0;
+}
+
+#endif
+
+static const struct i2c_device_id ricoh619_i2c_id[] = {
+       {"ricoh619", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ricoh619_i2c_id);
+
+static struct i2c_driver ricoh619_i2c_driver = {
+       .driver = {
+                  .name = "ricoh619",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = ricoh619_i2c_probe,
+       .remove = __devexit_p(ricoh619_i2c_remove),
+#ifdef CONFIG_PM
+       .suspend = ricoh619_i2c_suspend,
+       .resume = ricoh619_i2c_resume,
+#endif
+       .id_table = ricoh619_i2c_id,
+};
+
+
+static int __init ricoh619_i2c_init(void)
+{
+       int ret = -ENODEV;
+       ret = i2c_add_driver(&ricoh619_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register I2C driver: %d\n", ret);
+
+       return ret;
+}
+
+subsys_initcall_sync(ricoh619_i2c_init);
+
+static void __exit ricoh619_i2c_exit(void)
+{
+       i2c_del_driver(&ricoh619_i2c_driver);
+}
+
+module_exit(ricoh619_i2c_exit);
+
+MODULE_DESCRIPTION("RICOH RC5T619 PMU multi-function core driver");
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
old mode 100755 (executable)
new mode 100644 (file)
index 988b848..4935297
@@ -71,6 +71,13 @@ config WM8350_POWER
           Say Y here to enable support for the power management unit
          provided by the Wolfson Microelectronics WM8350 PMIC.
 
+config BATTERY_RICOH619
+       tristate "Ricoh RC5T619 PMIC battery driver"
+       depends on MFD_RICOH619 && I2C && GENERIC_HARDIRQS
+       help
+         Say Y to enable support for the battery control of the Ricoh RC5T619
+         Power Management device.
+
 config TEST_POWER
        tristate "Test power driver"
        help
index da73f4d6586e94799e70f3e1916fa99cba9fb548..fdc582a4f3c4cc8e2fc00f16fb8fbc92c6f4f6ec 100644 (file)
@@ -48,4 +48,4 @@ obj-$(CONFIG_BATTERY_RK30_ADC)  += rk30_adc_battery.o
 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
diff --git a/drivers/power/ricoh619-battery.c b/drivers/power/ricoh619-battery.c
new file mode 100644 (file)
index 0000000..0124ca5
--- /dev/null
@@ -0,0 +1,2338 @@
+/*
+ * drivers/power/ricoh619-battery.c
+ *
+ * Charger driver for RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/power/ricoh619_battery.h>
+#include <linux/power/ricoh61x_battery_init.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+
+/* define for function */
+#define ENABLE_FUEL_GAUGE_FUNCTION
+#define ENABLE_LOW_BATTERY_DETECTION
+#define ENABLE_FACTORY_MODE
+#define ENABLE_FG_KEEP_ON_MODE
+
+/* define for current limit. unit is mA */
+/* if value is "0", these settings set by OTP */
+#define RICOH619_MAX_CHARGE_CURRENT    0       /* mA */
+#define RICOH619_MAX_ADP_CURRENT       0       /* mA */
+#define RICOH619_MAX_USB_CURRENT       0       /* mA */
+#define RICOH619_CHARGE_COMPLETION_CURRENT     200     /* mA Range 50~200
+                                                        * (Step 50) */
+#define RICOH619_FULL_CHARGING_VOLTAGE         0       /* mv can set 4050,
+                                                        * 4100, 4150, 4200,
+                                                        * 4350(default 4100) */
+#define        RICOH619_RE_CHARGING_VOLTAGE            0       /* mv can set 3850,
+                                                        * 3900, 3950, 4000,
+                                                        * 4100(default 3900) */
+
+/* FG setting */
+#define        CUTOFF_VOL                              0       /* mV "0" means cutoff
+                                                        * voltage = original
+                                                        * OCV table value */
+#define RICOH619_REL1_SEL_VALUE                        64      /* mv Range 0~240
+                                                        * (Step 16) */
+
+enum int_type {
+       SYS_INT  = 0x01,
+       DCDC_INT = 0x02,
+       ADC_INT  = 0x08,
+       GPIO_INT = 0x10,
+       CHG_INT  = 0x40,
+};
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+/* define for FG parameter */
+#define RICOH619_MONITOR_START_TIME            15
+#define RICOH619_FG_RESET_TIME                 6
+#define RICOH619_FG_STABLE_TIME                        120
+#define RICOH619_DISPLAY_UPDATE_TIME           60
+#define RICOH619_SOCA_DISP_UPDATE_TIME         60
+#define RICOH619_MAX_RESET_SOC_DIFF            5
+
+/* define for FG status */
+enum {
+       RICOH619_SOCA_START,
+       RICOH619_SOCA_UNSTABLE,
+       RICOH619_SOCA_FG_RESET,
+       RICOH619_SOCA_DISP,
+       RICOH619_SOCA_STABLE,
+       RICOH619_SOCA_ZERO,
+};
+#endif
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+#define LOW_BATTERY_DETECTION_TIME             10
+#endif
+
+struct ricoh619_soca_info {
+       int Rbat;
+       int n_cap;
+       int ocv_table[11];
+       int soc;                /* Latest FG SOC value */
+       int displayed_soc;
+       int status;             /* SOCA status 0: Not initial; 5: Finished */
+       int stable_count;
+       int chg_status;         /* chg_status */
+       int soc_delta;          /* soc delta for status3(DISP) */
+       int cc_delta;
+       int last_soc;
+       int ready_fg;
+       int reset_count;
+       int reset_soc[3];
+};
+
+struct ricoh619_battery_info {
+       struct device      *dev;
+       struct power_supply     battery;
+       struct delayed_work     monitor_work;
+       struct delayed_work     usb_work;
+       struct delayed_work     displayed_work;
+       struct delayed_work     charge_stable_work;
+       struct delayed_work     changed_work;
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       struct delayed_work     low_battery_work;
+#endif
+
+       struct work_struct      irq_work;       /* for Charging & VUSB/VADP */
+       struct work_struct      usb_irq_work;   /* for ADC_VUSB */
+
+       struct workqueue_struct *monitor_wqueue;
+       struct workqueue_struct *workqueue;     /* for Charging & VUSB/VADP */
+       struct workqueue_struct *usb_workqueue; /* for ADC_VUSB */
+
+#ifdef ENABLE_FACTORY_MODE
+       struct delayed_work     factory_mode_work;
+       struct workqueue_struct *factory_mode_wqueue;
+#endif
+
+       struct mutex            lock;
+       unsigned long           monitor_time;
+       int             adc_vdd_mv;
+       int             multiple;
+       int             alarm_vol_mv;
+       int             status;
+       int             min_voltage;
+       int             max_voltage;
+       int             cur_voltage;
+       int             capacity;
+       int             battery_temp;
+       int             time_to_empty;
+       int             time_to_full;
+       int             chg_ctr;
+       int             chg_stat1;
+       unsigned        present:1;
+       u16             delay;
+       struct          ricoh619_soca_info *soca;
+       int             first_pwon;
+       bool            entry_factory_mode;
+};
+
+int charger_irq;
+/* this value is for mfd fucntion */
+int g_soc;
+int g_fg_on_mode;
+
+static void ricoh619_battery_work(struct work_struct *work)
+{
+       struct ricoh619_battery_info *info = container_of(work,
+               struct ricoh619_battery_info, monitor_work.work);
+
+       RICOH_FG_DBG("PMU: %s\n", __func__);
+       power_supply_changed(&info->battery);
+       queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+                          info->monitor_time);
+}
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+static int measure_vbatt_FG(struct ricoh619_battery_info *info, int *data);
+static int measure_Ibatt_FG(struct ricoh619_battery_info *info, int *data);
+static int calc_capacity(struct ricoh619_battery_info *info);
+static int get_OCV_init_Data(struct ricoh619_battery_info *info, int index);
+static int get_OCV_voltage(struct ricoh619_battery_info *info, int index);
+static int get_check_fuel_gauge_reg(struct ricoh619_battery_info *info,
+                                        int Reg_h, int Reg_l, int enable_bit);
+static int calc_capacity_in_period(struct ricoh619_battery_info *info,
+                                        int *cc_cap, bool *is_charging);
+
+/* check charge status.
+ * if CHG not Complete && SOC == 100 -> Stop charge
+ * if CHG Complete && SOC =! 100     -> SOC reset
+ */
+static int check_charge_status(struct ricoh619_battery_info *info)
+{
+       uint8_t status;
+       uint8_t supply_state;
+       uint8_t charge_state;
+       int ret = 0;
+       int current_SOC;
+
+       /* get  power supply status */
+       ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status);
+       if (ret < 0) {
+               dev_err(info->dev,
+                        "Error in reading the control register\n");
+               return ret;
+       }
+
+
+       charge_state = (status & 0x1F);
+       supply_state = ((status & 0xC0) >> 6);
+
+       current_SOC = (info->soca->displayed_soc + 50)/100;
+
+       if (charge_state == CHG_STATE_CHG_COMPLETE) {
+               /* check SOC */
+               if (current_SOC != 100) {
+                       ret = ricoh619_write(info->dev->parent,
+                                                FG_CTRL_REG, 0x51);
+                       if (ret < 0) {
+                               dev_err(info->dev, "Error in writing the control register\n");
+                               return ret;
+                       }
+                       info->soca->ready_fg = 0;
+
+                       info->soca->displayed_soc = 100 * 100;
+
+                       info->soca->status = RICOH619_SOCA_STABLE;
+               }
+
+       } else {        /* chg not complete */
+               if (current_SOC == 100) {
+                       ret = ricoh619_clr_bits(info->dev->parent,
+                                                CHGCTL1_REG, 0x03);
+                       if (ret < 0) {
+                               dev_err(info->dev, "Error in writing the control register\n");
+                               return ret;
+                       }
+                       info->soca->status = RICOH619_SOCA_STABLE;
+               } else {
+                       ret = ricoh619_set_bits(info->dev->parent,
+                                                CHGCTL1_REG, 0x03);
+                       if (ret < 0) {
+                               dev_err(info->dev, "Error in writing the control register\n");
+                               return ret;
+                       }
+               }
+       }
+       return ret;
+}
+
+static int calc_ocv(struct ricoh619_battery_info *info)
+{
+       int Vbat = 0;
+       int Ibat = 0;
+       int ret;
+       int ocv;
+
+       ret = measure_vbatt_FG(info, &Vbat);
+       ret = measure_Ibatt_FG(info, &Ibat);
+
+       ocv = Vbat - Ibat * info->soca->Rbat;
+
+       return ocv;
+}
+
+/**
+* Calculate Capacity in a period
+* - read CC_SUM & FA_CAP from Coulom Counter
+* -  and calculate Capacity.
+* @cc_cap: capacity in a period, unit 0.01%
+* @is_charging: Flag of charging current direction
+*               TRUE : charging (plus)
+*               FALSE: discharging (minus)
+**/
+static int calc_capacity_in_period(struct ricoh619_battery_info *info,
+                                        int *cc_cap, bool *is_charging)
+{
+       int err;
+       uint8_t cc_sum_reg[4];
+       uint8_t cc_clr[4] = {0, 0, 0, 0};
+       uint8_t fa_cap_reg[2];
+       uint16_t fa_cap;
+       uint32_t cc_sum;
+
+       *is_charging = true;    /* currrent state initialize -> charging */
+
+       if (info->entry_factory_mode)
+               return 0;
+
+       /* Disable Charging/Completion Interrupt */
+       err = ricoh619_set_bits(info->dev->parent,
+                                       RICOH619_INT_MSK_CHGSTS1, 0x01);
+       if (err < 0)
+               goto out;
+
+       /* In suspend - disable charging */
+       err = ricoh619_set_bits(info->dev->parent, RICOH619_CHG_CTL1, 0x08);
+       if (err < 0)
+               goto out;
+       /* CC_pause enter */
+       err = ricoh619_write(info->dev->parent, CC_CTRL_REG, 0x01);
+       if (err < 0)
+               goto out;
+       /* Read CC_SUM */
+       err = ricoh619_bulk_reads(info->dev->parent,
+                                       CC_SUMREG3_REG, 4, cc_sum_reg);
+       if (err < 0)
+               goto out;
+
+       /* CC_SUM <- 0 */
+       err = ricoh619_bulk_writes(info->dev->parent,
+                                       CC_SUMREG3_REG, 4, cc_clr);
+       if (err < 0)
+               goto out;
+
+       /* CC_pause exist */
+       err = ricoh619_write(info->dev->parent, CC_CTRL_REG, 0);
+       if (err < 0)
+               goto out;
+       /* out suspend - enable charging */
+       err = ricoh619_clr_bits(info->dev->parent, RICOH619_CHG_CTL1, 0x08);
+       if (err < 0)
+               goto out;
+
+       udelay(1000);
+
+       /* Clear Charging Interrupt status */
+       err = ricoh619_clr_bits(info->dev->parent,
+                                       RICOH619_INT_IR_CHGSTS1, 0x01);
+       if (err < 0)
+               goto out;
+
+       /* ricoh619_read(info->dev->parent, RICOH619_INT_IR_CHGSTS1, &val);
+       RICOH_FG_DBG("INT_IR_CHGSTS1 = 0x%x\n",val); */
+
+       /* Enable Charging Interrupt */
+       err = ricoh619_clr_bits(info->dev->parent,
+                                       RICOH619_INT_MSK_CHGSTS1, 0x01);
+       if (err < 0)
+               goto out;
+
+       /* Read FA_CAP */
+       err = ricoh619_bulk_reads(info->dev->parent,
+                                FA_CAP_H_REG, 2, fa_cap_reg);
+       if (err < 0)
+               goto out;
+
+       /* fa_cap = *(uint16_t*)fa_cap_reg & 0x7fff; */
+       fa_cap = (fa_cap_reg[0] << 8 | fa_cap_reg[1]) & 0x7fff;
+
+       /* calculation  two's complement of CC_SUM */
+       cc_sum = cc_sum_reg[0] << 24 | cc_sum_reg[1] << 16 |
+                               cc_sum_reg[2] << 8 | cc_sum_reg[3];
+
+       /* cc_sum = *(uint32_t*)cc_sum_reg; */
+       if (cc_sum & 0x80000000) {
+               cc_sum = (cc_sum^0xffffffff)+0x01;
+               *is_charging = false;           /* discharge */
+       }
+
+       *cc_cap = cc_sum*25/9/fa_cap;   /* CC_SUM/3600/FA_CAP */
+
+       return 0;
+out:
+       dev_err(info->dev, "Error !!-----\n");
+       return err;
+}
+
+static void ricoh619_displayed_work(struct work_struct *work)
+{
+       int err;
+       uint8_t val;
+       int soc_round;
+       int last_soc_round;
+       int last_disp_round;
+       int displayed_soc_temp;
+       int cc_cap = 0;
+       bool is_charging = true;
+
+       struct ricoh619_battery_info *info = container_of(work,
+       struct ricoh619_battery_info, displayed_work.work);
+
+       if (info->entry_factory_mode) {
+               info->soca->status = RICOH619_SOCA_STABLE;
+               info->soca->displayed_soc = -EINVAL;
+               info->soca->ready_fg = 0;
+               return;
+       }
+
+       mutex_lock(&info->lock);
+
+       if ((RICOH619_SOCA_START == info->soca->status)
+                || (RICOH619_SOCA_STABLE == info->soca->status))
+               info->soca->ready_fg = 1;
+
+       if (RICOH619_SOCA_STABLE == info->soca->status) {
+               info->soca->soc = calc_capacity(info) * 100;
+               info->soca->displayed_soc = info->soca->soc;
+       } else if (RICOH619_SOCA_DISP == info->soca->status) {
+
+               info->soca->soc = calc_capacity(info) * 100;
+
+               soc_round = info->soca->soc / 100;
+               last_soc_round = info->soca->last_soc / 100;
+               last_disp_round = (info->soca->displayed_soc + 50) / 100;
+
+               info->soca->soc_delta =
+                       info->soca->soc_delta + (soc_round - last_soc_round);
+
+               info->soca->last_soc = info->soca->soc;
+
+               /* six case */
+               if (last_disp_round == soc_round) {
+                       /* if SOC == DISPLAY move to stable */
+                       info->soca->displayed_soc = info->soca->soc ;
+                       info->soca->status = RICOH619_SOCA_STABLE;
+
+               } else if ((soc_round == 100) || (soc_round == 0)) {
+                       /* if SOC is 0% or 100% , finish display state*/
+                       info->soca->displayed_soc = info->soca->soc ;
+                       info->soca->status = RICOH619_SOCA_STABLE;
+
+               } else if ((info->soca->chg_status) ==
+                               (POWER_SUPPLY_STATUS_CHARGING)) {
+                       /* Charge */
+                       if (last_disp_round < soc_round) {
+                               /* Case 1 : Charge, Display < SOC */
+                               if (info->soca->soc_delta >= 1) {
+                                       info->soca->displayed_soc
+                                               = (last_disp_round
+                                               + info->soca->soc_delta)*100;
+                                       info->soca->soc_delta = 0;
+                               } else {
+                                       info->soca->displayed_soc
+                                               = (last_disp_round + 1)*100;
+                               }
+
+                               if (last_disp_round >= soc_round) {
+                                       info->soca->displayed_soc
+                                               = info->soca->soc ;
+                                       info->soca->status
+                                               = RICOH619_SOCA_STABLE;
+                               }
+                       } else if (last_disp_round > soc_round) {
+                               /* Case 2 : Charge, Display > SOC */
+                               if (info->soca->soc_delta >= 3) {
+                                       info->soca->displayed_soc =
+                                               (last_disp_round + 1)*100;
+                                       info->soca->soc_delta = 0;
+                               }
+                               if (last_disp_round <= soc_round) {
+                                       info->soca->displayed_soc
+                                               = info->soca->soc ;
+                                       info->soca->status
+                                       = RICOH619_SOCA_STABLE;
+                               }
+                       }
+               } else {
+                       /* Dis-Charge */
+                       if (last_disp_round > soc_round) {
+                               /* Case 3 : Dis-Charge, Display > SOC */
+                               if (info->soca->soc_delta <= -1) {
+                                       info->soca->displayed_soc
+                                               = (last_disp_round
+                                               + info->soca->soc_delta)*100;
+                                       info->soca->soc_delta = 0;
+                               } else {
+                                       info->soca->displayed_soc
+                                               = (last_disp_round - 1)*100;
+                               }
+                               if (last_disp_round <= soc_round) {
+                                       info->soca->displayed_soc
+                                               = info->soca->soc ;
+                                       info->soca->status
+                                               = RICOH619_SOCA_STABLE;
+                               }
+                       } else if (last_disp_round < soc_round) {
+                               /* dis Charge, Display < SOC */
+                               if (info->soca->soc_delta <= -3) {
+                                       info->soca->displayed_soc
+                                               = (last_disp_round - 1)*100;
+                                       info->soca->soc_delta = 0;
+                               }
+                               if (last_disp_round >= soc_round) {
+                                       info->soca->displayed_soc
+                                               = info->soca->soc ;
+                                       info->soca->status
+                                               = RICOH619_SOCA_STABLE;
+                               }
+                       }
+               }
+       } else if (RICOH619_SOCA_UNSTABLE == info->soca->status
+                || RICOH619_SOCA_FG_RESET == info->soca->status) {
+               /* No update */
+       } else if (RICOH619_SOCA_START == info->soca->status) {
+               err = ricoh619_read(info->dev->parent, PSWR_REG, &val);
+               val &= 0x7f;
+               if (info->first_pwon) {
+                       info->soca->soc = calc_capacity(info) * 100;
+                       if ((info->soca->soc == 0) && (calc_ocv(info)
+                                       < get_OCV_voltage(info, 0))) {
+                               info->soca->displayed_soc = 0;
+                               info->soca->status = RICOH619_SOCA_ZERO;
+                       } else {
+                               info->soca->displayed_soc = info->soca->soc;
+                               info->soca->status = RICOH619_SOCA_UNSTABLE;
+                       }
+               } else if (g_fg_on_mode && (val == 0x7f)) {
+                       info->soca->soc = calc_capacity(info) * 100;
+                       if ((info->soca->soc == 0) && (calc_ocv(info)
+                                       < get_OCV_voltage(info, 0))) {
+                               info->soca->displayed_soc = 0;
+                               info->soca->status = RICOH619_SOCA_ZERO;
+                       } else {
+                               info->soca->displayed_soc = info->soca->soc;
+                               info->soca->status = RICOH619_SOCA_STABLE;
+                       }
+               } else {
+                       info->soca->soc = val * 100;
+                       if ((err < 0) || (val == 0)) {
+                               dev_err(info->dev,
+                                        "Error in reading PSWR_REG %d\n", err);
+                               info->soca->soc
+                                        = calc_capacity(info) * 100 + 50;
+                       }
+
+                       err = calc_capacity_in_period(info, &cc_cap,
+                                                                &is_charging);
+                       if (err < 0)
+                               dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+                       info->soca->cc_delta
+                                = (is_charging == true) ? cc_cap : -cc_cap;
+                       if (calc_ocv(info) < get_OCV_voltage(info, 0)) {
+                               info->soca->displayed_soc = 0;
+                               info->soca->status = RICOH619_SOCA_ZERO;
+                       } else {
+                               displayed_soc_temp
+                                      = info->soca->soc + info->soca->cc_delta;
+                               displayed_soc_temp
+                                        = min(10000, displayed_soc_temp);
+                               displayed_soc_temp = max(0, displayed_soc_temp);
+                               info->soca->displayed_soc = displayed_soc_temp;
+                               info->soca->status = RICOH619_SOCA_UNSTABLE;
+                       }
+               }
+       } else if (RICOH619_SOCA_ZERO == info->soca->status) {
+               if (calc_ocv(info) > get_OCV_voltage(info, 0)) {
+                       err = ricoh619_write(info->dev->parent,
+                                                        FG_CTRL_REG, 0x51);
+                       if (err < 0)
+                               dev_err(info->dev, "Error in writing the control register\n");
+                       info->soca->status = RICOH619_SOCA_STABLE;
+                       info->soca->ready_fg = 0;
+               }
+               info->soca->displayed_soc = 0;
+       }
+
+       /* Ceck charge status */
+       err = check_charge_status(info);
+       if (err < 0)
+               dev_err(info->dev, "Error in writing the control register\n");
+
+       if (g_fg_on_mode
+                && (info->soca->status == RICOH619_SOCA_STABLE)) {
+               err = ricoh619_write(info->dev->parent, PSWR_REG, 0x7f);
+               if (err < 0)
+                       dev_err(info->dev, "Error in writing PSWR_REG\n");
+               g_soc = 0x7F;
+       } else {
+               val = (info->soca->displayed_soc + 50)/100;
+               val &= 0x7f;
+               err = ricoh619_write(info->dev->parent, PSWR_REG, val);
+               if (err < 0)
+                       dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+               g_soc = (info->soca->displayed_soc + 50)/100;
+
+               err = calc_capacity_in_period(info, &cc_cap, &is_charging);
+               if (err < 0)
+                       dev_err(info->dev, "Read cc_sum Error !!-----\n");
+       }
+
+       if (0 == info->soca->ready_fg)
+               queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+                                        RICOH619_FG_RESET_TIME * HZ);
+       else if (RICOH619_SOCA_DISP == info->soca->status)
+               queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+                                        RICOH619_SOCA_DISP_UPDATE_TIME * HZ);
+       else
+               queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+                                        RICOH619_DISPLAY_UPDATE_TIME * HZ);
+
+       mutex_unlock(&info->lock);
+
+       return;
+}
+
+static void ricoh619_stable_charge_countdown_work(struct work_struct *work)
+{
+       int ret;
+       int max = 0;
+       int min = 100;
+       int i;
+       struct ricoh619_battery_info *info = container_of(work,
+               struct ricoh619_battery_info, charge_stable_work.work);
+
+       if (info->entry_factory_mode)
+               return;
+
+       mutex_lock(&info->lock);
+       if (RICOH619_SOCA_FG_RESET == info->soca->status)
+               info->soca->ready_fg = 1;
+
+       if (2 <= info->soca->stable_count) {
+               if (3 == info->soca->stable_count
+                       && RICOH619_SOCA_FG_RESET == info->soca->status) {
+                       ret = ricoh619_write(info->dev->parent,
+                                                        FG_CTRL_REG, 0x51);
+                       if (ret < 0)
+                               dev_err(info->dev, "Error in writing the control register\n");
+                       info->soca->ready_fg = 0;
+               }
+               info->soca->stable_count = info->soca->stable_count - 1;
+               queue_delayed_work(info->monitor_wqueue,
+                                        &info->charge_stable_work,
+                                        RICOH619_FG_STABLE_TIME * HZ / 10);
+       } else if (0 >= info->soca->stable_count) {
+               /* Finished queue, ignore */
+       } else if (1 == info->soca->stable_count) {
+               if (RICOH619_SOCA_UNSTABLE == info->soca->status) {
+                       /* Judge if FG need reset or Not */
+                       info->soca->soc = calc_capacity(info) * 100;
+                       if (info->chg_ctr != 0) {
+                               queue_delayed_work(info->monitor_wqueue,
+                                        &info->charge_stable_work,
+                                        RICOH619_FG_STABLE_TIME * HZ / 10);
+                               mutex_unlock(&info->lock);
+                               return;
+                       }
+                       /* Do reset setting */
+                       ret = ricoh619_write(info->dev->parent,
+                                                FG_CTRL_REG, 0x51);
+                       if (ret < 0)
+                               dev_err(info->dev, "Error in writing the control register\n");
+
+                       info->soca->ready_fg = 0;
+                       info->soca->status = RICOH619_SOCA_FG_RESET;
+
+                       /* Delay for addition Reset Time (6s) */
+                       queue_delayed_work(info->monitor_wqueue,
+                                        &info->charge_stable_work,
+                                        RICOH619_FG_RESET_TIME*HZ);
+               } else if (RICOH619_SOCA_FG_RESET == info->soca->status) {
+                       info->soca->reset_soc[2] = info->soca->reset_soc[1];
+                       info->soca->reset_soc[1] = info->soca->reset_soc[0];
+                       info->soca->reset_soc[0] = calc_capacity(info) * 100;
+                       info->soca->reset_count++;
+
+                       if (info->soca->reset_count > 10) {
+                               /* Reset finished; */
+                               info->soca->soc = info->soca->reset_soc[0];
+                               info->soca->stable_count = 0;
+                               goto adjust;
+                       }
+
+                       for (i = 0; i < 3; i++) {
+                               if (max < info->soca->reset_soc[i]/100)
+                                       max = info->soca->reset_soc[i]/100;
+                               if (min > info->soca->reset_soc[i]/100)
+                                       min = info->soca->reset_soc[i]/100;
+                       }
+
+                       if ((info->soca->reset_count > 3) && ((max - min)
+                                       < RICOH619_MAX_RESET_SOC_DIFF)) {
+                               /* Reset finished; */
+                               info->soca->soc = info->soca->reset_soc[0];
+                               info->soca->stable_count = 0;
+                               goto adjust;
+                       } else {
+                               /* Do reset setting */
+                               ret = ricoh619_write(info->dev->parent,
+                                                        FG_CTRL_REG, 0x51);
+                               if (ret < 0)
+                                       dev_err(info->dev, "Error in writing the control register\n");
+
+                               info->soca->ready_fg = 0;
+
+                               /* Delay for addition Reset Time (6s) */
+                               queue_delayed_work(info->monitor_wqueue,
+                                                &info->charge_stable_work,
+                                                RICOH619_FG_RESET_TIME*HZ);
+                       }
+               /* Finished queue From now, select FG as result; */
+               } else if (RICOH619_SOCA_START == info->soca->status) {
+                       /* Normal condition */
+               } else { /* other state ZERO/DISP/STABLE */
+                       info->soca->stable_count = 0;
+               }
+
+               mutex_unlock(&info->lock);
+               return;
+
+adjust:
+               info->soca->last_soc = info->soca->soc;
+               info->soca->status = RICOH619_SOCA_DISP;
+
+       }
+       mutex_unlock(&info->lock);
+       return;
+}
+
+/* Initial setting of FuelGauge SOCA function */
+static int ricoh619_init_fgsoca(struct ricoh619_battery_info *info)
+{
+       int i;
+       int err;
+       uint8_t val;
+       uint8_t val2;
+
+       for (i = 0; i <= 10; i = i+1) {
+               info->soca->ocv_table[i] = get_OCV_voltage(info, i);
+               RICOH_FG_DBG("PMU: %s : * %d0%% voltage = %d uV\n",
+                                __func__, i, info->soca->ocv_table[i]);
+       }
+
+       for (i = 0; i < 3; i = i+1)
+               info->soca->reset_soc[i] = 0;
+       info->soca->reset_count = 0;
+
+       if (info->first_pwon) {
+
+               err = ricoh619_read(info->dev->parent, CHGISET_REG, &val);
+               if (err < 0)
+                       dev_err(info->dev,
+                       "Error in read CHGISET_REG%d\n", err);
+
+               err = ricoh619_write(info->dev->parent, CHGISET_REG, 0);
+               if (err < 0)
+                       dev_err(info->dev,
+                       "Error in writing CHGISET_REG%d\n", err);
+               msleep(1000);
+
+
+               err = ricoh619_write(info->dev->parent,
+                                                FG_CTRL_REG, 0x51);
+               if (err < 0)
+                       dev_err(info->dev, "Error in writing the control register\n");
+
+               msleep(6000);
+
+               err = ricoh619_write(info->dev->parent, CHGISET_REG, val);
+               if (err < 0)
+                       dev_err(info->dev,
+                       "Error in writing CHGISET_REG%d\n", err);
+       }
+       
+       /* Rbat : Transfer */
+       info->soca->Rbat = get_OCV_init_Data(info, 12) * 1000 / 512
+                                                        * 5000 / 4095;
+       info->soca->n_cap = get_OCV_init_Data(info, 11);
+
+       info->soca->displayed_soc = 0;
+       info->soca->ready_fg = 0;
+       info->soca->soc_delta = 0;
+       info->soca->status = RICOH619_SOCA_START;
+       /* stable count down 11->2, 1: reset; 0: Finished; */
+       info->soca->stable_count = 11;
+
+#ifdef ENABLE_FG_KEEP_ON_MODE
+       g_fg_on_mode = 1;
+#else
+       g_fg_on_mode = 0;
+#endif
+
+       /* Start first Display job */
+       queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+                                                  RICOH619_FG_RESET_TIME*HZ);
+
+       /* Start first Waiting stable job */
+       queue_delayed_work(info->monitor_wqueue, &info->charge_stable_work,
+                  RICOH619_FG_STABLE_TIME*HZ/10);
+
+       RICOH_FG_DBG("PMU: %s : * Rbat = %d mOhm   n_cap = %d mAH\n",
+                        __func__, info->soca->Rbat, info->soca->n_cap);
+       return 1;
+}
+#endif
+
+static void ricoh619_changed_work(struct work_struct *work)
+{
+       struct ricoh619_battery_info *info = container_of(work,
+               struct ricoh619_battery_info, changed_work.work);
+
+       RICOH_FG_DBG("PMU: %s\n", __func__);
+       power_supply_changed(&info->battery);
+
+       return;
+}
+
+#ifdef ENABLE_FACTORY_MODE
+/*------------------------------------------------------*/
+/* Factory Mode                                                */
+/*    Check Battery exist or not                       */
+/*    If not, disabled Rapid to Complete State change  */
+/*------------------------------------------------------*/
+static int ricoh619_factory_mode(struct ricoh619_battery_info *info)
+{
+       int ret = 0;
+       uint8_t val = 0;
+
+       ret = ricoh619_read(info->dev->parent, RICOH619_INT_MON_CHGCTR, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               return ret;
+       }
+       if (!(val & 0x01)) /* No Adapter connected */
+               return ret;
+
+       /* Rapid to Complete State change disable */
+       ret = ricoh619_write(info->dev->parent, RICOH619_CHG_CTL1, 0xe3);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in writing the control register\n");
+               return ret;
+       }
+
+       /* Wait 1s for checking Charging State */
+       queue_delayed_work(info->factory_mode_wqueue, &info->factory_mode_work,
+                        1*HZ);
+
+       return ret;
+}
+
+static void check_charging_state_work(struct work_struct *work)
+{
+       struct ricoh619_battery_info *info = container_of(work,
+               struct ricoh619_battery_info, factory_mode_work.work);
+
+       int ret = 0;
+       uint8_t val = 0;
+       int chargeCurrent = 0;
+
+       ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               return;
+       }
+
+
+       chargeCurrent = get_check_fuel_gauge_reg(info, CC_AVERAGE1_REG,
+                                                CC_AVERAGE0_REG, 0x3fff);
+       if (chargeCurrent < 0) {
+               dev_err(info->dev, "Error in reading the FG register\n");
+               return;
+       }
+
+       /* Repid State && Charge Current about 0mA */
+       if (((chargeCurrent > 0x3ffc && chargeCurrent < 0x3fff)
+               || chargeCurrent < 0x05) && val == 0x43) {
+               RICOH_FG_DBG("PMU:%s --- No battery !! Enter Factory mode ---\n"
+                               , __func__);
+               info->entry_factory_mode = true;
+               return; /* Factory Mode */
+       }
+
+       /* Return Normal Mode --> Rapid to Complete State change enable */
+       ret = ricoh619_write(info->dev->parent, RICOH619_CHG_CTL1, 0xa3);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in writing the control register\n");
+               return;
+       }
+       RICOH_FG_DBG("PMU:%s --- Battery exist !! Return Normal mode ---0x%2x\n"
+                       , __func__, val);
+
+       return;
+}
+#endif /* ENABLE_FACTORY_MODE */
+
+static int Calc_Linear_Interpolation(int x0, int y0, int x1, int y1, int y)
+{
+       int     alpha;
+       int x;
+
+       alpha = (y - y0)*100 / (y1 - y0);
+
+       x = ((100 - alpha) * x0 + alpha * x1) / 100;
+
+       return x;
+}
+
+static int ricoh619_set_OCV_table(struct ricoh619_battery_info *info)
+{
+       int             ret = 0;
+       int             ocv_table[11];
+       int             i, j;
+       int             available_cap;
+       int             temp;
+       int             start_par;
+       int             percent_step;
+       int             OCV_percent_new[11];
+
+       if (CUTOFF_VOL == 0) {  /* normal version */
+       } else {        /*Slice cutoff voltage version. */
+
+               /* get ocv table. this table is calculated by Apprication */
+               for (i = 0; i <= 10; i = i+1) {
+                       temp = (battery_init_para[i*2]<<8)
+                                | (battery_init_para[i*2+1]);
+                       /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+                       temp = ((temp * 50000 * 10 / 4095) + 5) / 10;
+                       ocv_table[i] = temp;
+               }
+
+
+               /* Check Start % */
+               for (i = 1; i < 11; i++) {
+                       if (ocv_table[i] >= CUTOFF_VOL * 10) {
+                               /* unit is 0.001% */
+                               start_par = Calc_Linear_Interpolation(
+                                       (i-1)*1000, ocv_table[i-1], i*1000,
+                                        ocv_table[i], (CUTOFF_VOL * 10));
+                               i = 11;
+                       }
+               }
+               /* calc new ocv percent */
+               percent_step = (10000 - start_par) / 10;
+
+               for (i = 0; i < 11; i++) {
+                       OCV_percent_new[i]
+                                = start_par + percent_step*(i - 0);
+               }
+
+               /* calc new ocv voltage */
+               for (i = 0; i < 11; i++) {
+                       for (j = 1; j < 11; j++) {
+                               if (1000*j >= OCV_percent_new[i]) {
+                                       temp = Calc_Linear_Interpolation(
+                                               ocv_table[j-1], (j-1)*1000,
+                                                ocv_table[j] , j*1000,
+                                                OCV_percent_new[i]);
+
+                                       temp = temp * 4095 / 50000;
+
+                                       battery_init_para[i*2 + 1] = temp;
+                                       battery_init_para[i*2] = temp >> 8;
+
+                                       j = 11;
+                               }
+                       }
+               }
+
+               /* calc available capacity */
+               /* get avilable capacity */
+               /* battery_init_para23-24 is designe capacity */
+               available_cap = (battery_init_para[22]<<8)
+                                        | (battery_init_para[23]);
+
+               available_cap = available_cap
+                        * ((10000 - start_par) / 100) / 100 ;
+
+
+               battery_init_para[23] =  available_cap;
+               battery_init_para[22] =  available_cap >> 8;
+
+       }
+       ret = ricoh619_bulk_writes_bank1(info->dev->parent,
+                        BAT_INIT_TOP_REG, 32, battery_init_para);
+       if (ret < 0) {
+               dev_err(info->dev, "batterry initialize error\n");
+               return ret;
+       }
+
+       return 1;
+}
+
+/* Initial setting of battery */
+static int ricoh619_init_battery(struct ricoh619_battery_info *info)
+{
+       int ret = 0;
+       uint8_t val;
+       /* Need to implement initial setting of batery and error */
+       /* -------------------------- */
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+
+       /* set kanwa state */
+       if (RICOH619_REL1_SEL_VALUE > 240)
+               val = 0x0F;
+       else
+               val = RICOH619_REL1_SEL_VALUE / 16 ;
+
+       val = 0x20 + val;
+
+       ret = ricoh619_write_bank1(info->dev->parent, BAT_REL_SEL_REG, val);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in writing the OCV Tabler\n");
+               return ret;
+       }
+
+       ret = ricoh619_read(info->dev->parent, FG_CTRL_REG, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               return ret;
+       }
+
+       val = (val & 0x10) >> 4;
+       info->first_pwon = (val == 0) ? 1 : 0;
+
+       ret = ricoh619_set_OCV_table(info);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in writing the OCV Tabler\n");
+               return ret;
+       }
+
+       ret = ricoh619_write(info->dev->parent, FG_CTRL_REG, 0x11);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in writing the control register\n");
+               return ret;
+       }
+
+#endif
+
+       if (info->alarm_vol_mv < 2700 || info->alarm_vol_mv > 3400) {
+               dev_err(info->dev, "alarm_vol_mv is out of range!\n");
+               return -1;
+       }
+
+       return ret;
+}
+
+/* Initial setting of charger */
+static int ricoh619_init_charger(struct ricoh619_battery_info *info)
+{
+       int err;
+       uint8_t val;
+       uint8_t val2;
+
+       info->chg_ctr = 0;
+       info->chg_stat1 = 0;
+
+       /* In suspend - disable charging */
+       err = ricoh619_clr_bits(info->dev->parent,CHGCTL1_REG, 0x03);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing the control register\n");
+               goto free_device;
+       }
+       
+       if (RICOH619_MAX_ADP_CURRENT != 0) {
+               /* Change ADP Current to 2.5A. */
+               err = ricoh619_write(info->dev->parent, 0xb6,
+                                                (RICOH619_MAX_ADP_CURRENT-1)/100);
+               if (err < 0) {
+                       dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+                                                                                err);
+                       goto free_device;
+               }
+       }
+
+       if (RICOH619_MAX_USB_CURRENT != 0) {
+               /* Set Max Change USB Current (0xB7) */
+               err = ricoh619_write(info->dev->parent, REGISET2_REG,
+                                                (RICOH619_MAX_USB_CURRENT-1)/100);
+               if (err < 0) {
+                       dev_err(info->dev,
+                        "Error in writing RICOH619_MAX_USB_CURRENT %d\n", err);
+                       goto free_device;
+               }
+       }
+
+       /* Set Charge competion current    (0xB8) */
+       /* this value for bit 4-0 */
+       if (RICOH619_MAX_CHARGE_CURRENT != 0) {
+               val = (RICOH619_MAX_CHARGE_CURRENT-1)/100;
+       } else {
+               err = ricoh619_read(info->dev->parent, CHGISET_REG, &val);
+               if (err < 0) {
+                       dev_err(info->dev,
+                       "Error in read RICOH619_MAX_CHARGE_CURRENT %d\n", err);
+                       goto free_device;
+               }
+               val &= 0x3F;
+       }
+       
+       /* Set Charge competion current    (0xB8) */
+       /* this value for bit 7-6 */
+       if(RICOH619_CHARGE_COMPLETION_CURRENT != 0) {
+               val2 = (RICOH619_CHARGE_COMPLETION_CURRENT - 50) / 50;
+       } else {
+               err = ricoh619_read(info->dev->parent, CHGISET_REG, &val2);
+               if (err < 0) {
+                       dev_err(info->dev,
+                       "Error in read RICOH619_MAX_CHARGE_CURRENT %d\n", err);
+                       goto free_device;
+               }
+               val2 &= 0xC0;
+       }
+       val = val + (val2 << 6);
+       err = ricoh619_write(info->dev->parent, CHGISET_REG, val);
+       if (err < 0) {
+               dev_err(info->dev,
+                "Error in writing RICOH619_MAX_CHARGE_CURRENT %d\n", err);
+               goto free_device;
+       }
+
+       /* Change Charger Voltege to 4.2V. Recharge Point to 4.1V */
+       /* for define FULL charging voltage (bit 6~4)*/
+       if (RICOH619_FULL_CHARGING_VOLTAGE != 0) {
+               if (RICOH619_FULL_CHARGING_VOLTAGE < 4050)
+                       val2 = 0x00;
+               else if (RICOH619_FULL_CHARGING_VOLTAGE > 4200)
+                       val2 = 0x04;
+               else
+                       val2 = (RICOH619_FULL_CHARGING_VOLTAGE - 4050) / 50;
+       } else {
+               err = ricoh619_read(info->dev->parent, BATSET2_REG, &val2);
+               if (err < 0) {
+                       dev_err(info->dev,
+                       "Error in read RICOH619_FULL_CHARGE_VOLTAGE %d\n", err);
+                       goto free_device;
+               }
+               val2 &= 0x70;
+       }
+
+       /* for define re-charging voltage (bit 2~0)*/
+       if (RICOH619_RE_CHARGING_VOLTAGE != 0) {
+               if (RICOH619_RE_CHARGING_VOLTAGE < 3850)
+                       val = 0x00;
+               else if (RICOH619_RE_CHARGING_VOLTAGE > 4000)
+                       val = 0x04;
+               else
+                       val = (RICOH619_RE_CHARGING_VOLTAGE - 3850) / 50;
+       } else {
+               err = ricoh619_read(info->dev->parent, BATSET2_REG, &val);
+               if (err < 0) {
+                       dev_err(info->dev,
+                       "Error in read RICOH619_RE_CHARGE_VOLTAGE %d\n", err);
+                       goto free_device;
+               }
+               val &= 0x07;
+       }
+
+       val = val + (val2 << 4);
+
+       err = ricoh619_write(info->dev->parent, BATSET2_REG, val);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing RICOH619_RE_CHARGE_VOLTAGE %d\n",
+                                                                        err);
+               goto free_device;
+       }
+
+       /* out suspend - enable charging */
+       err = ricoh619_set_bits(info->dev->parent,CHGCTL1_REG, 0x03);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing the control register\n");
+               goto free_device;
+       }
+
+       /* Set rising edge setting ([1:0]=01b)for INT in charging */
+       /*  and rising edge setting ([3:2]=01b)for charge completion */
+       err = ricoh619_read(info->dev->parent, RICOH619_CHG_STAT_DETMOD1, &val);
+       if (err < 0) {
+               dev_err(info->dev, "Error in reading CHG_STAT_DETMOD1 %d\n",
+                                                                err);
+               goto free_device;
+       }
+       val &= 0xf0;
+       val |= 0x05;
+       err = ricoh619_write(info->dev->parent, RICOH619_CHG_STAT_DETMOD1, val);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing CHG_STAT_DETMOD1 %d\n",
+                                                                err);
+               goto free_device;
+       }
+
+       /* Unmask In charging/charge completion */
+       err = ricoh619_write(info->dev->parent, RICOH619_INT_MSK_CHGSTS1, 0xfc);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+                                                                err);
+               goto free_device;
+       }
+
+       /* Set both edge for VUSB([3:2]=11b)/VADP([1:0]=11b) detect */
+       err = ricoh619_read(info->dev->parent, RICOH619_CHG_CTRL_DETMOD1, &val);
+       if (err < 0) {
+               dev_err(info->dev, "Error in reading CHG_CTRL_DETMOD1 %d\n",
+                                                                err);
+               goto free_device;
+       }
+       val &= 0xf0;
+       val |= 0x0f;
+       err = ricoh619_write(info->dev->parent, RICOH619_CHG_CTRL_DETMOD1, val);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing CHG_CTRL_DETMOD1 %d\n",
+                                                                err);
+               goto free_device;
+       }
+
+       /* Unmask In VUSB/VADP completion */
+       err = ricoh619_write(info->dev->parent, RICOH619_INT_MSK_CHGCTR, 0xfc);
+       if (err < 0) {
+               dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+                                                                        err);
+               goto free_device;
+       }
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       /* Set ADRQ=00 to stop ADC */
+       ricoh619_write(info->dev->parent, RICOH619_ADC_CNT3, 0x0);
+       /* Enable VSYS threshold Low interrupt */
+       ricoh619_write(info->dev->parent, RICOH619_INT_EN_ADC1, 0x10);
+       /* Set ADC auto conversion interval 250ms */
+       ricoh619_write(info->dev->parent, RICOH619_ADC_CNT2, 0x0);
+       /* Enable VSYS pin conversion in auto-ADC */
+       ricoh619_write(info->dev->parent, RICOH619_ADC_CNT1, 0x10);
+       /* Set VSYS threshold low voltage = 3.50v */
+       ricoh619_write(info->dev->parent, RICOH619_ADC_VSYS_THL, 0x77);
+       /* Start auto-mode & average 4-time conversion mode for ADC */
+       ricoh619_write(info->dev->parent, RICOH619_ADC_CNT3, 0x28);
+       /* Enable master ADC INT */
+       ricoh619_set_bits(info->dev->parent, RICOH619_INTC_INTEN, ADC_INT);
+#endif
+
+free_device:
+       return err;
+}
+
+
+static int get_power_supply_status(struct ricoh619_battery_info *info)
+{
+       uint8_t status;
+       uint8_t supply_state;
+       uint8_t charge_state;
+       int ret = 0;
+
+       /* get  power supply status */
+       ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               return ret;
+       }
+
+       charge_state = (status & 0x1F);
+       supply_state = ((status & 0xC0) >> 6);
+
+       if (supply_state == SUPPLY_STATE_BAT) {
+               info->soca->chg_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       } else {
+               switch (charge_state) {
+               case    CHG_STATE_CHG_OFF:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_DISCHARGING;
+                               break;
+               case    CHG_STATE_CHG_READY_VADP:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_CHG_TRICKLE:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_CHARGING;
+                               break;
+               case    CHG_STATE_CHG_RAPID:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_CHARGING;
+                               break;
+               case    CHG_STATE_CHG_COMPLETE:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_FULL;
+                               break;
+               case    CHG_STATE_SUSPEND:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_DISCHARGING;
+                               break;
+               case    CHG_STATE_VCHG_OVER_VOL:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_DISCHARGING;
+                               break;
+               case    CHG_STATE_BAT_ERROR:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_NO_BAT:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_BAT_OVER_VOL:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_BAT_TEMP_ERR:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_DIE_ERR:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_DIE_SHUTDOWN:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_DISCHARGING;
+                               break;
+               case    CHG_STATE_NO_BAT2:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               case    CHG_STATE_CHG_READY_VUSB:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+               default:
+                               info->soca->chg_status
+                                       = POWER_SUPPLY_STATUS_UNKNOWN;
+                               break;
+               }
+       }
+
+       return info->soca->chg_status;
+}
+
+static void charger_irq_work(struct work_struct *work)
+{
+       struct ricoh619_battery_info *info
+                = container_of(work, struct ricoh619_battery_info, irq_work);
+       int ret = 0;
+       RICOH_FG_DBG("PMU:%s In\n", __func__);
+
+       power_supply_changed(&info->battery);
+
+       mutex_lock(&info->lock);
+       info->chg_ctr = 0;
+       info->chg_stat1 = 0;
+
+       /* Enable Interrupt for VADP */
+       ret = ricoh619_clr_bits(info->dev->parent,
+                                        RICOH619_INT_MSK_CHGCTR, 0x01);
+       if (ret < 0)
+               dev_err(info->dev,
+                        "%s(): Error in enable charger mask INT %d\n",
+                        __func__, ret);
+
+       /* Enable Interrupt for Charging & complete */
+       ret = ricoh619_write(info->dev->parent, RICOH619_INT_MSK_CHGSTS1, 0xfc);
+       if (ret < 0)
+               dev_err(info->dev,
+                        "%s(): Error in enable charger mask INT %d\n",
+                        __func__, ret);
+
+       mutex_unlock(&info->lock);
+       RICOH_FG_DBG("PMU:%s Out\n", __func__);
+}
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+static void low_battery_irq_work(struct work_struct *work)
+{
+       struct ricoh619_battery_info *info = container_of(work,
+                struct ricoh619_battery_info, low_battery_work.work);
+
+       int ret = 0;
+
+       RICOH_FG_DBG("PMU:%s In\n", __func__);
+
+       power_supply_changed(&info->battery);
+
+       /* Enable VADP threshold Low interrupt */
+       ricoh619_write(info->dev->parent, RICOH619_INT_EN_ADC1, 0x10);
+       if (ret < 0)
+               dev_err(info->dev,
+                        "%s(): Error in enable adc mask INT %d\n",
+                        __func__, ret);
+}
+#endif
+
+static void usb_det_irq_work(struct work_struct *work)
+{
+       struct ricoh619_battery_info *info = container_of(work,
+                struct ricoh619_battery_info, usb_irq_work);
+       int ret = 0;
+       uint8_t sts;
+       int time =0;
+
+       RICOH_FG_DBG("PMU:%s In\n", __func__);
+
+       power_supply_changed(&info->battery);
+
+       mutex_lock(&info->lock);
+
+       /* Enable Interrupt for VUSB */
+       ret = ricoh619_clr_bits(info->dev->parent,
+                                        RICOH619_INT_MSK_CHGCTR, 0x02);
+       if (ret < 0)
+               dev_err(info->dev,
+                        "%s(): Error in enable charger mask INT %d\n",
+                        __func__, ret);
+
+       mutex_unlock(&info->lock);
+
+       ret = ricoh619_read(info->dev->parent, RICOH619_INT_MON_CHGCTR, &sts);
+       if (ret < 0)
+               dev_err(info->dev, "Error in reading the control register\n");
+
+       sts &= 0x02;
+       if (sts) {
+       
+       } else {
+               /*********************/
+               /* No process ??     */
+               /*********************/
+       }
+       
+       RICOH_FG_DBG("PMU:%s Out\n", __func__);
+}
+
+extern void rk28_send_wakeup_key(void); 
+static irqreturn_t charger_in_isr(int irq, void *battery_info)
+{
+       struct ricoh619_battery_info *info = battery_info;
+       printk("PMU:%s\n", __func__);
+
+       info->chg_stat1 |= 0x01;
+       queue_work(info->workqueue, &info->irq_work);
+        rk28_send_wakeup_key(); 
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_complete_isr(int irq, void *battery_info)
+{
+       struct ricoh619_battery_info *info = battery_info;
+       printk("PMU:%s\n", __func__);
+
+       info->chg_stat1 |= 0x02;
+       queue_work(info->workqueue, &info->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_usb_isr(int irq, void *battery_info)
+{
+       struct ricoh619_battery_info *info = battery_info;
+       printk("PMU:%s\n", __func__);
+
+       info->chg_ctr |= 0x02;
+       queue_work(info->usb_workqueue, &info->usb_irq_work);
+        rk28_send_wakeup_key(); 
+
+       if (RICOH619_SOCA_UNSTABLE == info->soca->status
+               || RICOH619_SOCA_FG_RESET == info->soca->status)
+               info->soca->stable_count = 11;
+       
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_adp_isr(int irq, void *battery_info)
+{
+       struct ricoh619_battery_info *info = battery_info;
+       struct ricoh619 *ricoh619 = g_ricoh619;
+       printk("PMU:%s\n", __func__);
+
+       info->chg_ctr |= 0x01;
+       queue_work(info->workqueue, &info->irq_work);
+       rk28_send_wakeup_key(); 
+       /* clr usb det irq */
+       ricoh619_clr_bits(ricoh619->dev, RICOH619_INT_IR_CHGCTR,
+                                                        info->chg_ctr);
+
+       /* set adp limit current 2A */
+       ricoh619_write(ricoh619->dev, 0xb6, 0x13);
+       /* set charge current 2A */
+       ricoh619_write(ricoh619->dev, 0xb8, 0x13);
+
+       if (RICOH619_SOCA_UNSTABLE == info->soca->status
+               || RICOH619_SOCA_FG_RESET == info->soca->status)
+               info->soca->stable_count = 11;
+
+       return IRQ_HANDLED;
+}
+
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+/*************************************************************/
+/* for Detecting Low Battery                                 */
+/*************************************************************/
+
+static irqreturn_t adc_vsysl_isr(int irq, void *battery_info)
+{
+
+       struct ricoh619_battery_info *info = battery_info;
+
+#if 0
+       RICOH_FG_DBG("PMU:%s\n", __func__);
+
+       queue_delayed_work(info->monitor_wqueue, &info->low_battery_work,
+                                       LOW_BATTERY_DETECTION_TIME*HZ);
+
+#endif
+
+       RICOH_FG_DBG("PMU:%s\n", __func__);
+       ricoh619_write(info->dev->parent, RICOH619_INT_EN_ADC1, 0x10);
+       rk28_send_wakeup_key(); 
+
+       return IRQ_HANDLED;
+}
+#endif
+
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+static int get_check_fuel_gauge_reg(struct ricoh619_battery_info *info,
+                                        int Reg_h, int Reg_l, int enable_bit)
+{
+       uint8_t get_data_h, get_data_l;
+       int old_data, current_data;
+       int i;
+       int ret = 0;
+
+       old_data = 0;
+
+       for (i = 0; i < 5 ; i++) {
+               ret = ricoh619_read(info->dev->parent, Reg_h, &get_data_h);
+               if (ret < 0) {
+                       dev_err(info->dev, "Error in reading the control register\n");
+                       return ret;
+               }
+
+               ret = ricoh619_read(info->dev->parent, Reg_l, &get_data_l);
+               if (ret < 0) {
+                       dev_err(info->dev, "Error in reading the control register\n");
+                       return ret;
+               }
+
+               current_data = ((get_data_h & 0xff) << 8) | (get_data_l & 0xff);
+               current_data = (current_data & enable_bit);
+
+               if (current_data == old_data)
+                       return current_data;
+               else
+                       old_data = current_data;
+       }
+
+       return current_data;
+}
+
+static int calc_capacity(struct ricoh619_battery_info *info)
+{
+       uint8_t capacity;
+       int temp;
+       int ret = 0;
+
+       /* get remaining battery capacity from fuel gauge */
+       ret = ricoh619_read(info->dev->parent, SOC_REG, &capacity);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               return ret;
+       }
+
+       temp = capacity;
+
+       return temp;            /* Unit is 1% */
+}
+
+static int get_battery_temp(struct ricoh619_battery_info *info)
+{
+       int ret = 0;
+       int sign_bit;
+
+       ret = get_check_fuel_gauge_reg(info, TEMP_1_REG, TEMP_2_REG, 0x0fff);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+               return ret;
+       }
+
+       /* bit3 of 0xED(TEMP_1) is sign_bit */
+       sign_bit = ((ret & 0x0800) >> 11);
+
+       ret = (ret & 0x07ff);
+
+       if (sign_bit == 0)      /* positive value part */
+               /* conversion unit */
+               /* 1 unit is 0.0625 degree and retun unit
+                * should be 0.1 degree,
+                */
+               ret = ret * 625  / 1000;
+       else    /*negative value part */
+               ret = -1 * ret * 625 / 1000;
+
+       return ret;
+}
+
+static int get_time_to_empty(struct ricoh619_battery_info *info)
+{
+       int ret = 0;
+
+       ret = get_check_fuel_gauge_reg(info, TT_EMPTY_H_REG, TT_EMPTY_L_REG,
+                                                               0xffff);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+               return ret;
+       }
+
+       /* conversion unit */
+       /* 1unit is 1miniute and return nnit should be 1 second */
+       ret = ret * 60;
+
+       return ret;
+}
+
+static int get_time_to_full(struct ricoh619_battery_info *info)
+{
+       int ret = 0;
+
+       ret = get_check_fuel_gauge_reg(info, TT_FULL_H_REG, TT_FULL_L_REG,
+                                                               0xffff);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+               return ret;
+       }
+
+       ret = ret * 60;
+
+       return  ret;
+}
+
+/* battery voltage is get from Fuel gauge */
+static int measure_vbatt_FG(struct ricoh619_battery_info *info, int *data)
+{
+       int ret = 0;
+
+       ret = get_check_fuel_gauge_reg(info, VOLTAGE_1_REG, VOLTAGE_2_REG,
+                                                               0x0fff);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+               return ret;
+       }
+
+       *data = ret;
+       /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+       *data = *data * 50000 / 4095;
+       /* return unit should be 1uV */
+       *data = *data * 100;
+
+       return ret;
+}
+
+static int measure_Ibatt_FG(struct ricoh619_battery_info *info, int *data)
+{
+       int ret = 0;
+
+       ret =  get_check_fuel_gauge_reg(info, CC_AVERAGE1_REG,
+                                                CC_AVERAGE0_REG, 0x3fff);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+               return ret;
+       }
+
+       *data = (ret > 0x1fff) ? (ret - 0x4000) : ret;
+       return ret;
+}
+
+static int get_OCV_init_Data(struct ricoh619_battery_info *info, int index)
+{
+       int ret = 0;
+       ret =  (battery_init_para[index*2]<<8) | (battery_init_para[index*2+1]);
+       return ret;
+}
+
+static int get_OCV_voltage(struct ricoh619_battery_info *info, int index)
+{
+       int ret = 0;
+       ret =  get_OCV_init_Data(info, index);
+       /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+       ret = ret * 50000 / 4095;
+       /* return unit should be 1uV */
+       ret = ret * 100;
+       return ret;
+}
+
+#else
+/* battery voltage is get from ADC */
+static int measure_vbatt_ADC(struct ricoh619_battery_info *info, int *data)
+{
+       int     i;
+       uint8_t data_l = 0, data_h = 0;
+       int ret;
+
+       /* ADC interrupt enable */
+       ret = ricoh619_set_bits(info->dev->parent, INTEN_REG, 0x08);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in setting the control register bit\n");
+               goto err;
+       }
+
+       /* enable interrupt request of single mode */
+       ret = ricoh619_set_bits(info->dev->parent, EN_ADCIR3_REG, 0x01);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in setting the control register bit\n");
+               goto err;
+       }
+
+       /* single request */
+       ret = ricoh619_write(info->dev->parent, ADCCNT3_REG, 0x10);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in writing the control register\n");
+               goto err;
+       }
+
+       for (i = 0; i < 5; i++) {
+               usleep(1000);
+               RICOH_FG_DBG("ADC conversion times: %d\n", i);
+               /* read completed flag of ADC */
+               ret = ricoh619_read(info->dev->parent, EN_ADCIR3_REG, &data_h);
+               if (ret < 0) {
+                       dev_err(info->dev, "Error in reading the control register\n");
+                       goto err;
+               }
+
+               if (data_h & 0x01)
+                       goto    done;
+       }
+
+       dev_err(info->dev, "ADC conversion too long!\n");
+       goto err;
+
+done:
+       ret = ricoh619_read(info->dev->parent, VBATDATAH_REG, &data_h);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               goto err;
+       }
+
+       ret = ricoh619_read(info->dev->parent, VBATDATAL_REG, &data_l);
+       if (ret < 0) {
+               dev_err(info->dev, "Error in reading the control register\n");
+               goto err;
+       }
+
+       *data = ((data_h & 0xff) << 4) | (data_l & 0x0f);
+       /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+       *data = *data * 5000 / 4095;
+       /* return unit should be 1uV */
+       *data = *data * 1000;
+
+       return 0;
+
+err:
+       return -1;
+}
+#endif
+
+/*
+static void ricoh619_external_power_changed(struct power_supply *psy)
+{
+       struct ricoh619_battery_info *info;
+
+       info = container_of(psy, struct ricoh619_battery_info, battery);
+       queue_delayed_work(info->monitor_wqueue,
+                          &info->changed_work, HZ / 2);
+       return;
+}
+*/
+
+static int ricoh619_batt_get_prop(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct ricoh619_battery_info *info = dev_get_drvdata(psy->dev->parent);
+       int data = 0;
+       int ret = 0;
+       uint8_t status;
+
+       mutex_lock(&info->lock);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status);
+               if (ret < 0) {
+                       dev_err(info->dev, "Error in reading the control register\n");
+                       mutex_unlock(&info->lock);
+                       return ret;
+               }
+               if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+                       val->intval = (status & 0x40 ? 1 : 0);
+               else if (psy->type == POWER_SUPPLY_TYPE_USB)
+                       val->intval = (status & 0x80 ? 1 : 0);
+               break;
+       /* this setting is same as battery driver of 584 */
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = get_power_supply_status(info);
+               val->intval = ret;
+               info->status = ret;
+               /* RICOH_FG_DBG("Power Supply Status is %d\n",
+                                                       info->status); */
+               break;
+
+       /* this setting is same as battery driver of 584 */
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = info->present;
+               break;
+
+       /* current voltage is get from fuel gauge */
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               /* return real vbatt Voltage */
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+               if (info->soca->ready_fg)
+                       ret = measure_vbatt_FG(info, &data);
+               else {
+                       val->intval = -EINVAL;
+                       RICOH_FG_DBG( "battery voltage is not ready\n");
+                       break;
+               }
+#else
+               ret = measure_vbatt_ADC(info, &data);
+#endif
+               val->intval = data;
+               /* convert unit uV -> mV */
+               info->cur_voltage = data / 1000;
+               RICOH_FG_DBG( "battery voltage is %d mV\n",
+                                               info->cur_voltage);
+               break;
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+       /* current battery capacity is get from fuel gauge */
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = (info->soca->displayed_soc + 50)/100;
+               info->capacity = (info->soca->displayed_soc + 50)/100;
+               /* RICOH_FG_DBG("battery capacity is %d%%\n",
+                                                       info->capacity); */
+               break;
+
+       /* current temperature of battery */
+       case POWER_SUPPLY_PROP_TEMP:
+               if (info->soca->ready_fg) {
+                       ret = get_battery_temp(info);
+                       val->intval = ret;
+                       info->battery_temp = ret/10;
+                       RICOH_FG_DBG( "battery temperature is %d degree\n", info->battery_temp);
+               } else {
+                       val->intval = -EINVAL;
+                       RICOH_FG_DBG("battery temperature is not ready\n");
+               }
+               break;
+
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+               if (info->soca->ready_fg) {
+                       ret = get_time_to_empty(info);
+                       val->intval = ret;
+                       info->time_to_empty = ret/60;
+                       RICOH_FG_DBG("time of empty battery is %d minutes\n", info->time_to_empty);
+               } else {
+                       val->intval = -EINVAL;
+                       RICOH_FG_DBG( "time of empty battery is not ready\n");
+               }
+               break;
+
+        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+               if (info->soca->ready_fg) {
+                       ret = get_time_to_full(info);
+                       val->intval = ret;
+                       info->time_to_full = ret/60;
+                       RICOH_FG_DBG( "time of full battery is %d minutes\n", info->time_to_full);
+               } else {
+                       val->intval = -EINVAL;
+                       RICOH_FG_DBG("time of full battery is not ready\n");
+               }
+               break;
+#endif
+        case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               ret = 0;
+               break;
+
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               ret = 0;
+               break;
+
+       default:
+               mutex_unlock(&info->lock);
+               return -ENODEV;
+       }
+
+       mutex_unlock(&info->lock);
+
+       return ret;
+}
+
+static enum power_supply_property ricoh619_batt_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+       POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+#endif
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_HEALTH,
+};
+
+static enum power_supply_property ricoh619_power_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+struct power_supply    powerac = {
+               .name = "acpwr",
+               .type = POWER_SUPPLY_TYPE_MAINS,
+               .properties = ricoh619_power_props,
+               .num_properties = ARRAY_SIZE(ricoh619_power_props),
+               .get_property = ricoh619_batt_get_prop,
+};
+
+struct power_supply    powerusb = {
+               .name = "usbpwr",
+               .type = POWER_SUPPLY_TYPE_USB,
+               .properties = ricoh619_power_props,
+               .num_properties = ARRAY_SIZE(ricoh619_power_props),
+               .get_property = ricoh619_batt_get_prop,
+};
+
+static __devinit int ricoh619_battery_probe(struct platform_device *pdev)
+{
+       struct ricoh619_battery_info *info;
+       struct ricoh619_battery_platform_data *pdata;
+       int ret;
+
+       RICOH_FG_DBG("PMU: %s\n", __func__);
+
+       info = kzalloc(sizeof(struct ricoh619_battery_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->soca = kzalloc(sizeof(struct ricoh619_soca_info), GFP_KERNEL);
+               if (!info->soca)
+                       return -ENOMEM;
+
+       info->dev = &pdev->dev;
+       info->status = POWER_SUPPLY_STATUS_CHARGING;
+       pdata = pdev->dev.platform_data;
+       info->monitor_time = pdata->monitor_time * HZ;
+       info->alarm_vol_mv = pdata->alarm_vol_mv;
+       info->adc_vdd_mv = ADC_VDD_MV;          /* 2800; */
+       info->min_voltage = MIN_VOLTAGE;        /* 3100; */
+       info->max_voltage = MAX_VOLTAGE;        /* 4200; */
+       info->delay = 500;
+       info->entry_factory_mode = false;
+
+       mutex_init(&info->lock);
+       platform_set_drvdata(pdev, info);
+
+       info->battery.name = "battery";
+       info->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       info->battery.properties = ricoh619_batt_props;
+       info->battery.num_properties = ARRAY_SIZE(ricoh619_batt_props);
+       info->battery.get_property = ricoh619_batt_get_prop;
+       info->battery.set_property = NULL;
+/*     info->battery.external_power_changed
+                = ricoh619_external_power_changed; */
+
+       /* Disable Charger/ADC interrupt */
+       ret = ricoh619_clr_bits(info->dev->parent, RICOH619_INTC_INTEN,
+                                                        CHG_INT | ADC_INT);
+       if (ret)
+               goto out;
+
+       ret = ricoh619_init_battery(info);
+       if (ret)
+               goto out;
+
+#ifdef ENABLE_FACTORY_MODE
+       info->factory_mode_wqueue
+               = create_singlethread_workqueue("ricoh619_factory_mode");
+       INIT_DELAYED_WORK_DEFERRABLE(&info->factory_mode_work,
+                                        check_charging_state_work);
+
+       ret = ricoh619_factory_mode(info);
+       if (ret)
+               goto out;
+
+#endif
+
+       ret = power_supply_register(&pdev->dev, &info->battery);
+
+       if (ret)
+               info->battery.dev->parent = &pdev->dev;
+
+       ret = power_supply_register(&pdev->dev, &powerac);
+       ret = power_supply_register(&pdev->dev, &powerusb);
+
+       info->monitor_wqueue
+               = create_singlethread_workqueue("ricoh619_battery_monitor");
+       INIT_DELAYED_WORK_DEFERRABLE(&info->monitor_work,
+                                        ricoh619_battery_work);
+       INIT_DELAYED_WORK_DEFERRABLE(&info->displayed_work,
+                                        ricoh619_displayed_work);
+       INIT_DELAYED_WORK_DEFERRABLE(&info->charge_stable_work,
+                                        ricoh619_stable_charge_countdown_work);
+       INIT_DELAYED_WORK(&info->changed_work, ricoh619_changed_work);
+       queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+                                       RICOH619_MONITOR_START_TIME*HZ);
+
+
+       /* Charger IRQ workqueue settings */
+       charger_irq = pdata->irq;
+
+       info->workqueue = create_singlethread_workqueue("rc5t619_charger_in");
+       INIT_WORK(&info->irq_work, charger_irq_work);
+
+       ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FONCHGINT,
+                                       NULL, charger_in_isr, IRQF_ONESHOT,
+                                               "rc5t619_charger_in", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't get CHG_INT IRQ for chrager: %d\n",
+                                                                       ret);
+               goto out;
+       }
+       info->workqueue = create_singlethread_workqueue("rc5t619_charger_in");
+       INIT_WORK(&info->irq_work, charger_irq_work);
+
+       ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT,
+                                               NULL, charger_complete_isr,
+                                       IRQF_ONESHOT, "rc5t619_charger_comp",
+                                                               info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't get CHG_COMP IRQ for chrager: %d\n",
+                                                                        ret);
+               goto out;
+       }
+
+       ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT,
+                                       NULL, charger_usb_isr, IRQF_ONESHOT,
+                                               "rc5t619_usb_det", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't get USB_DET IRQ for chrager: %d\n",
+                                                                        ret);
+               goto out;
+       }
+
+       ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FVADPDETSINT,
+                                       NULL, charger_adp_isr, IRQF_ONESHOT,
+                                               "rc5t619_adp_det", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "Can't get ADP_DET IRQ for chrager: %d\n", ret);
+               goto out;
+       }
+
+       info->usb_workqueue
+               = create_singlethread_workqueue("rc5t619_usb_det");
+       INIT_WORK(&info->usb_irq_work, usb_det_irq_work);
+
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       ret = request_threaded_irq(charger_irq + RICOH619_IRQ_VSYSLIR,
+                                       NULL, adc_vsysl_isr, IRQF_ONESHOT,
+                                               "rc5t619_adc_vsysl", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "Can't get ADC_VSYSL IRQ for chrager: %d\n", ret);
+               goto out;
+       }
+       INIT_DELAYED_WORK_DEFERRABLE(&info->low_battery_work,
+                                        low_battery_irq_work);
+#endif
+
+       /* Charger init and IRQ setting */
+       ret = ricoh619_init_charger(info);
+       if (ret)
+               goto out;
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+       ret = ricoh619_init_fgsoca(info);
+#endif
+
+       /* Enable Charger interrupt */
+       ricoh619_set_bits(info->dev->parent, RICOH619_INTC_INTEN, CHG_INT);
+
+       return 0;
+
+out:
+       kfree(info);
+       return ret;
+}
+
+static int __devexit ricoh619_battery_remove(struct platform_device *pdev)
+{
+       struct ricoh619_battery_info *info = platform_get_drvdata(pdev);
+       uint8_t val;
+       int ret;
+       int err;
+       int cc_cap = 0;
+       bool is_charging = true;
+
+       if (g_fg_on_mode
+                && (info->soca->status == RICOH619_SOCA_STABLE)) {
+               err = ricoh619_write(info->dev->parent, PSWR_REG, 0x7f);
+               if (err < 0)
+                       dev_err(info->dev, "Error in writing PSWR_REG\n");
+               g_soc = 0x7f;
+       } else {
+               val = (info->soca->displayed_soc + 50)/100;
+               val &= 0x7f;
+               ret = ricoh619_write(info->dev->parent, PSWR_REG, val);
+               if (ret < 0)
+                       dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+               g_soc = (info->soca->displayed_soc + 50)/100;
+
+               ret = calc_capacity_in_period(info, &cc_cap, &is_charging);
+               if (ret < 0)
+                       dev_err(info->dev, "Read cc_sum Error !!-----\n");
+       }
+
+       if (g_fg_on_mode == 0) {
+               ret = ricoh619_clr_bits(info->dev->parent,
+                                        FG_CTRL_REG, 0x01);
+               if (ret < 0)
+                       dev_err(info->dev, "Error in clr FG EN\n");
+       }
+
+       cancel_delayed_work(&info->monitor_work);
+       cancel_delayed_work(&info->charge_stable_work);
+       cancel_delayed_work(&info->changed_work);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       cancel_delayed_work(&info->low_battery_work);
+#endif
+
+       flush_work(&info->irq_work);
+       flush_work(&info->usb_irq_work);
+
+       flush_workqueue(info->monitor_wqueue);
+       flush_workqueue(info->workqueue);
+       flush_workqueue(info->usb_workqueue);
+
+       destroy_workqueue(info->monitor_wqueue);
+       destroy_workqueue(info->workqueue);
+       destroy_workqueue(info->usb_workqueue);
+
+       power_supply_unregister(&info->battery);
+       kfree(info);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ricoh619_battery_suspend(struct device *dev)
+{
+       struct ricoh619_battery_info *info = dev_get_drvdata(dev);
+       uint8_t val;
+       int ret;
+       int err;
+       int cc_cap = 0;
+       bool is_charging = true;
+
+       if (g_fg_on_mode
+                && (info->soca->status == RICOH619_SOCA_STABLE)) {
+               err = ricoh619_write(info->dev->parent, PSWR_REG, 0x7f);
+               if (err < 0)
+                       dev_err(info->dev, "Error in writing PSWR_REG\n");
+                g_soc = 0x7F;
+       } else {
+               val = (info->soca->displayed_soc + 50)/100;
+               val &= 0x7f;
+               ret = ricoh619_write(info->dev->parent, PSWR_REG, val);
+               if (ret < 0)
+                       dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+               g_soc = (info->soca->displayed_soc + 50)/100;
+
+               ret = calc_capacity_in_period(info, &cc_cap, &is_charging);
+               if (ret < 0)
+                       dev_err(info->dev, "Read cc_sum Error !!-----\n");
+       }
+
+       disable_irq(charger_irq + RICOH619_IRQ_FONCHGINT);
+       disable_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT);
+       disable_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT);
+       disable_irq(charger_irq + RICOH619_IRQ_FVADPDETSINT);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       disable_irq(charger_irq + RICOH619_IRQ_VSYSLIR);
+#endif
+
+       cancel_delayed_work_sync(&info->monitor_work);
+       cancel_delayed_work_sync(&info->displayed_work);
+       cancel_delayed_work_sync(&info->charge_stable_work);
+       cancel_delayed_work_sync(&info->changed_work);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       cancel_delayed_work_sync(&info->low_battery_work);
+#endif
+       cancel_work_sync(&info->irq_work);
+       cancel_work_sync(&info->usb_irq_work);
+
+       flush_workqueue(info->monitor_wqueue);
+       flush_workqueue(info->workqueue);
+       flush_workqueue(info->usb_workqueue);
+
+       return 0;
+}
+
+static int ricoh619_battery_resume(struct device *dev)
+{
+       struct ricoh619_battery_info *info = dev_get_drvdata(dev);
+       uint8_t val;
+       int ret;
+       int displayed_soc_temp;
+       int cc_cap = 0;
+       bool is_charging = true;
+       int i;
+
+       if (info->entry_factory_mode) {
+               info->soca->displayed_soc = -EINVAL;
+       } else if (RICOH619_SOCA_STABLE == info->soca->status) {
+               info->soca->soc = calc_capacity(info) * 100;
+               info->soca->displayed_soc = info->soca->soc;
+       } else if (RICOH619_SOCA_ZERO == info->soca->status) {
+               if (calc_ocv(info) > get_OCV_voltage(info, 0)) {
+                       ret = ricoh619_read(info->dev->parent, PSWR_REG, &val);
+                       val &= 0x7f;
+                       info->soca->soc = val * 100;
+                       if ((ret < 0) || (val == 0)) {
+                               dev_err(info->dev,
+                                        "Error in reading PSWR_REG %d\n", ret);
+                               info->soca->soc
+                                        = calc_capacity(info) * 100 + 50;
+                       }
+
+                       ret = calc_capacity_in_period(info, &cc_cap,
+                                                                &is_charging);
+                       if (ret < 0)
+                               dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+                       info->soca->cc_delta
+                                = (is_charging == true) ? cc_cap : -cc_cap;
+
+                       displayed_soc_temp
+                                = info->soca->soc + info->soca->cc_delta;
+                       displayed_soc_temp = min(10000, displayed_soc_temp);
+                       displayed_soc_temp = max(0, displayed_soc_temp);
+                       info->soca->displayed_soc = displayed_soc_temp;
+
+                       ret = ricoh619_write(info->dev->parent,
+                                                        FG_CTRL_REG, 0x51);
+                       if (ret < 0)
+                               dev_err(info->dev, "Error in writing the control register\n");
+                       info->soca->ready_fg = 0;
+                       info->soca->status = RICOH619_SOCA_FG_RESET;
+
+               } else
+                       info->soca->displayed_soc = 0;
+       } else {
+               ret = ricoh619_read(info->dev->parent, PSWR_REG, &val);
+               val &= 0x7f;
+               info->soca->soc = val * 100;
+               if ((ret < 0) || (val == 0)) {
+                       dev_err(info->dev,
+                                "Error in reading PSWR_REG %d\n", ret);
+                       info->soca->soc
+                                = calc_capacity(info) * 100 + 50;
+               }
+
+               ret = calc_capacity_in_period(info, &cc_cap, &is_charging);
+               if (ret < 0)
+                       dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+               info->soca->cc_delta = (is_charging == true) ? cc_cap : -cc_cap;
+
+               displayed_soc_temp = info->soca->soc + info->soca->cc_delta;
+               displayed_soc_temp = min(10000, displayed_soc_temp);
+               displayed_soc_temp = max(0, displayed_soc_temp);
+               info->soca->displayed_soc = displayed_soc_temp;
+               if (RICOH619_SOCA_DISP == info->soca->status)
+                       info->soca->last_soc = calc_capacity(info) * 100;
+       }
+
+       power_supply_changed(&info->battery);
+       queue_delayed_work(info->monitor_wqueue, &info->displayed_work, HZ);
+
+       if (RICOH619_SOCA_UNSTABLE == info->soca->status) {
+               info->soca->stable_count = 10;
+               queue_delayed_work(info->monitor_wqueue,
+                                        &info->charge_stable_work,
+                                        RICOH619_FG_STABLE_TIME*HZ/10);
+       } else if (RICOH619_SOCA_FG_RESET == info->soca->status) {
+               info->soca->stable_count = 1;
+
+               for (i = 0; i < 3; i = i+1)
+                       info->soca->reset_soc[i] = 0;
+               info->soca->reset_count = 0;
+
+               queue_delayed_work(info->monitor_wqueue,
+                                        &info->charge_stable_work,
+                                        RICOH619_FG_RESET_TIME*HZ);
+       }
+
+       queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+                                                info->monitor_time);
+
+       enable_irq(charger_irq + RICOH619_IRQ_FONCHGINT);
+       enable_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT);
+       enable_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT);
+       enable_irq(charger_irq + RICOH619_IRQ_FVADPDETSINT);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+       enable_irq(charger_irq + RICOH619_IRQ_VSYSLIR);
+#endif
+       return 0;
+}
+
+static const struct dev_pm_ops ricoh619_battery_pm_ops = {
+       .suspend        = ricoh619_battery_suspend,
+       .resume         = ricoh619_battery_resume,
+};
+#endif
+
+static struct platform_driver ricoh619_battery_driver = {
+       .driver = {
+                               .name   = "ricoh619-battery",
+                               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+                               .pm     = &ricoh619_battery_pm_ops,
+#endif
+       },
+       .probe  = ricoh619_battery_probe,
+       .remove = __devexit_p(ricoh619_battery_remove),
+};
+
+static int __init ricoh619_battery_init(void)
+{
+       RICOH_FG_DBG("PMU: %s\n", __func__);
+       return platform_driver_register(&ricoh619_battery_driver);
+}
+subsys_initcall_sync(ricoh619_battery_init);
+
+static void __exit ricoh619_battery_exit(void)
+{
+       platform_driver_unregister(&ricoh619_battery_driver);
+}
+module_exit(ricoh619_battery_exit);
+
+MODULE_DESCRIPTION("RICOH619 Battery driver");
+MODULE_ALIAS("platform:ricoh619-battery");
+MODULE_LICENSE("GPL");
old mode 100755 (executable)
new mode 100644 (file)
index e01f5af..b890398
@@ -171,6 +171,13 @@ config REGULATOR_WM8994
          This driver provides support for the voltage regulators on the
          WM8994 CODEC.
 
+config REGULATOR_RICOH619
+       tristate "RICOH 619 Power regulators"
+       depends on MFD_RICOH619
+       default n
+       help
+         This driver supports regulator driver for RICOH619 PMIC.
+
 config REGULATOR_DA903X
        tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
        depends on PMIC_DA903X
old mode 100755 (executable)
new mode 100644 (file)
index 21b93d3..13f27a9
@@ -53,5 +53,6 @@ obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 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
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ricoh619-regulator.c b/drivers/regulator/ricoh619-regulator.c
new file mode 100644 (file)
index 0000000..3c5d433
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * drivers/regulator/ricoh619-regulator.c
+ *
+ * Regulator driver for RICOH619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *     Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+/*#define DEBUG                        1*/
+/*#define VERBOSE_DEBUG                1*/
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/regulator/ricoh619-regulator.h>
+
+struct ricoh619_regulator {
+       int             id;
+       int             sleep_id;
+       /* Regulator register address.*/
+       u8              reg_en_reg;
+       u8              en_bit;
+       u8              reg_disc_reg;
+       u8              disc_bit;
+       u8              vout_reg;
+       u8              vout_mask;
+       u8              vout_reg_cache;
+       u8              sleep_reg;
+       u8              eco_reg;
+       u8              eco_bit;
+       u8              eco_slp_reg;
+       u8              eco_slp_bit;
+
+       /* chip constraints on regulator behavior */
+       int                     min_uV;
+       int                     max_uV;
+       int                     step_uV;
+       int                     nsteps;
+
+       /* regulator specific turn-on delay */
+       u16                     delay;
+
+       /* used by regulator core */
+       struct regulator_desc   desc;
+
+       /* Device */
+       struct device           *dev;
+};
+
+//static unsigned int ricoh619_suspend_status = 0;
+
+static inline struct device *to_ricoh619_dev(struct regulator_dev *rdev)
+{
+       return rdev_get_dev(rdev)->parent->parent;
+}
+
+static int ricoh619_regulator_enable_time(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+
+       return ri->delay;
+}
+
+static int ricoh619_reg_is_enabled(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       uint8_t control;
+       int ret;
+
+       ret = ricoh619_read(parent, ri->reg_en_reg, &control);
+       if (ret < 0) {
+               dev_err(&rdev->dev, "Error in reading the control register\n");
+               return ret;
+       }
+       return (((control >> ri->en_bit) & 1) == 1);
+}
+
+static int ricoh619_reg_enable(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+       ret = ricoh619_set_bits(parent, ri->reg_en_reg, (1 << ri->en_bit));
+       if (ret < 0) {
+               dev_err(&rdev->dev, "Error in updating the STATE register\n");
+               return ret;
+       }
+       udelay(ri->delay);
+       return ret;
+}
+
+static int ricoh619_reg_disable(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+       ret = ricoh619_clr_bits(parent, ri->reg_en_reg, (1 << ri->en_bit));
+       if (ret < 0)
+               dev_err(&rdev->dev, "Error in updating the STATE register\n");
+
+       return ret;
+}
+
+static int ricoh619_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+
+       return ri->min_uV + (ri->step_uV * index);
+}
+
+static int __ricoh619_set_s_voltage(struct device *parent,
+               struct ricoh619_regulator *ri, int min_uV, int max_uV)
+{
+       int vsel;
+       int ret;
+
+       if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV))
+               return -EDOM;
+
+       vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV;
+       if (vsel > ri->nsteps)
+               return -EDOM;
+
+       ret = ricoh619_update(parent, ri->sleep_reg, vsel, ri->vout_mask);
+       if (ret < 0)
+               dev_err(ri->dev, "Error in writing the sleep register\n");
+       return ret;
+}
+
+static int __ricoh619_set_voltage(struct device *parent,
+               struct ricoh619_regulator *ri, int min_uV, int max_uV,
+               unsigned *selector)
+{
+       int vsel;
+       int ret;
+       uint8_t vout_val;
+
+       if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV))
+               return -EDOM;
+
+       vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV;
+       if (vsel > ri->nsteps)
+               return -EDOM;
+
+       if (selector)
+               *selector = vsel;
+
+       vout_val = (ri->vout_reg_cache & ~ri->vout_mask) |
+                               (vsel & ri->vout_mask);
+       ret = ricoh619_write(parent, ri->vout_reg, vout_val);
+       if (ret < 0)
+               dev_err(ri->dev, "Error in writing the Voltage register\n");
+       else
+               ri->vout_reg_cache = vout_val;
+
+       return ret;
+}
+
+static int ricoh619_set_voltage(struct regulator_dev *rdev,
+               int min_uV, int max_uV, unsigned *selector)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+
+//     if(ricoh619_suspend_status)
+//             return -EBUSY;
+
+       return __ricoh619_set_voltage(parent, ri, min_uV, max_uV, selector);
+}
+
+static int ricoh619_set_suspend_voltage(struct regulator_dev *rdev,
+               int uV)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+
+       return __ricoh619_set_s_voltage(parent, ri, uV, uV);
+}
+
+static int ricoh619_get_voltage(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       uint8_t vsel;
+
+       vsel = ri->vout_reg_cache & ri->vout_mask;
+       return ri->min_uV + vsel * ri->step_uV;
+}
+
+ int ricoh619_regulator_enable_eco_mode(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+
+       ret = ricoh619_set_bits(parent, ri->eco_reg, (1 << ri->eco_bit));
+       if (ret < 0)
+               dev_err(&rdev->dev, "Error Enable LDO eco mode\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_enable_eco_mode);
+
+int ricoh619_regulator_disable_eco_mode(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+
+       ret = ricoh619_clr_bits(parent, ri->eco_reg, (1 << ri->eco_bit));
+       if (ret < 0)
+               dev_err(&rdev->dev, "Error Disable LDO eco mode\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_disable_eco_mode);
+
+int ricoh619_regulator_enable_eco_slp_mode(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+
+       ret = ricoh619_set_bits(parent, ri->eco_slp_reg, (1 << ri->eco_slp_bit));
+       if (ret < 0)
+               dev_err(&rdev->dev, "Error Enable LDO eco mode in d during sleep\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_enable_eco_slp_mode);
+
+int ricoh619_regulator_disable_eco_slp_mode(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+
+       ret = ricoh619_clr_bits(parent, ri->eco_slp_reg, (1 << ri->eco_slp_bit));
+       if (ret < 0)
+               dev_err(&rdev->dev, "Error Enable LDO eco mode in d during sleep\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_disable_eco_slp_mode);
+
+static unsigned int ricoh619_dcdc_get_mode(struct regulator_dev *rdev)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+       uint8_t control;
+       u8 mask = 0x30;
+       
+       ret = ricoh619_read(parent, ri->reg_en_reg,&control);
+        if (ret < 0) {
+                return ret;
+        }
+       control=(control & mask) >> 4;
+       switch (control) {
+       case 1:
+               return REGULATOR_MODE_FAST;
+       case 0:
+               return REGULATOR_MODE_NORMAL;
+       case 2:
+               return REGULATOR_MODE_STANDBY;
+       case 4:
+               return REGULATOR_MODE_NORMAL;
+       default:
+               return -1;
+       }
+
+}
+static int ricoh619_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+       struct device *parent = to_ricoh619_dev(rdev);
+       int ret;
+       uint8_t control;
+       
+       ret = ricoh619_read(parent, ri->reg_en_reg,&control);
+       switch(mode)
+       {
+       case REGULATOR_MODE_FAST:
+               return ricoh619_write(parent, ri->reg_en_reg, ((control & 0xef) | 0x10));
+       case REGULATOR_MODE_NORMAL:
+               return ricoh619_write(parent, ri->reg_en_reg, (control & 0xcf));
+       case REGULATOR_MODE_STANDBY:
+               return ricoh619_write(parent, ri->reg_en_reg, ((control & 0xdf) | 0x20));       
+       default:
+               printk("error:pmu_619 only powersave pwm psm mode\n");
+               return -EINVAL;
+       }
+       
+
+}
+
+static int ricoh619_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,   unsigned int old_selector,
+                                    unsigned int new_selector)
+{
+       int old_volt, new_volt;
+       
+       old_volt = ricoh619_list_voltage(rdev, old_selector);
+       if (old_volt < 0)
+               return old_volt;
+       
+       new_volt = ricoh619_list_voltage(rdev, new_selector);
+       if (new_volt < 0)
+               return new_volt;
+
+       return DIV_ROUND_UP(abs(old_volt - new_volt)*2, 14000);
+}
+
+
+static struct regulator_ops ricoh619_ops = {
+       .list_voltage                   = ricoh619_list_voltage,
+       .set_voltage                    = ricoh619_set_voltage,
+       .get_voltage                    = ricoh619_get_voltage,
+       .set_suspend_voltage = ricoh619_set_suspend_voltage,
+       .set_voltage_time_sel = ricoh619_dcdc_set_voltage_time_sel,
+       .get_mode = ricoh619_dcdc_get_mode,
+       .set_mode = ricoh619_dcdc_set_mode,
+       .enable                         = ricoh619_reg_enable,
+       .disable                                = ricoh619_reg_disable,
+       .is_enabled                     = ricoh619_reg_is_enabled,
+};
+
+#define RICOH619_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \
+               _vout_mask, _ds_reg, _min_uv, _max_uv, _step_uV, _nsteps,    \
+               _ops, _delay, _eco_reg, _eco_bit, _eco_slp_reg, _eco_slp_bit)           \
+{                                                              \
+       .reg_en_reg     = _en_reg,                              \
+       .en_bit         = _en_bit,                              \
+       .reg_disc_reg   = _disc_reg,                            \
+       .disc_bit       = _disc_bit,                            \
+       .vout_reg       = _vout_reg,                            \
+       .vout_mask      = _vout_mask,                           \
+       .sleep_reg      = _ds_reg,                              \
+       .min_uV         = _min_uv,                      \
+       .max_uV         = _max_uv ,                     \
+       .step_uV        = _step_uV,                             \
+       .nsteps         = _nsteps,                              \
+       .delay          = _delay,                               \
+       .id             = RICOH619_ID_##_id,                    \
+       .sleep_id       = RICOH619_DS_##_id,                    \
+       .eco_reg                        =  _eco_reg,                            \
+       .eco_bit                        =  _eco_bit,                            \
+       .eco_slp_reg            =  _eco_slp_reg,                                \
+       .eco_slp_bit            =  _eco_slp_bit,                                \
+       .desc = {                                               \
+               .name = ricoh619_rails(_id),                    \
+               .id = RICOH619_ID_##_id,                        \
+               .n_voltages = _nsteps,                          \
+               .ops = &_ops,                                   \
+               .type = REGULATOR_VOLTAGE,                      \
+               .owner = THIS_MODULE,                           \
+       },                                                      \
+}
+
+static struct ricoh619_regulator ricoh619_regulator[] = {
+       RICOH619_REG(DC1, 0x2C, 0, 0x2C, 1, 0x36, 0xFF, 0x3B,
+                       600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(DC2, 0x2E, 0, 0x2E, 1, 0x37, 0xFF, 0x3C,
+                       600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(DC3, 0x30, 0, 0x30, 1, 0x38, 0xFF, 0x3D,
+                       600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(DC4, 0x32, 0, 0x32, 1, 0x39, 0xFF, 0x3E,
+                       600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(DC5, 0x34, 0, 0x34, 1, 0x3A, 0xFF, 0x3F,
+                       600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+                       
+       RICOH619_REG(LDO1, 0x44, 0, 0x46, 0, 0x4C, 0x7F, 0x58,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x48, 0, 0x4A, 0),
+
+       RICOH619_REG(LDO2, 0x44, 1, 0x46, 1, 0x4D, 0x7F, 0x59,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x48, 1, 0x4A, 1),
+
+       RICOH619_REG(LDO3, 0x44, 2, 0x46, 2, 0x4E, 0x7F, 0x5A,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x48, 2, 0x4A, 2),
+
+       RICOH619_REG(LDO4, 0x44, 3, 0x46, 3, 0x4F, 0x7F, 0x5B,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x48, 3, 0x4A, 3),
+
+       RICOH619_REG(LDO5, 0x44, 4, 0x46, 4, 0x50, 0x7F, 0x5C,
+                       600000, 3500000, 25000, 0x74, ricoh619_ops, 500,
+                       0x48, 4, 0x4A, 4),
+
+       RICOH619_REG(LDO6, 0x44, 5, 0x46, 5, 0x51, 0x7F, 0x5D,
+                       600000, 3500000, 25000, 0x74, ricoh619_ops, 500,
+                       0x48, 5, 0x4A, 5),
+
+       RICOH619_REG(LDO7, 0x44, 6, 0x46, 6, 0x52, 0x7F, 0x5E,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(LDO8, 0x44, 7, 0x46, 7, 0x53, 0x7F, 0x5F,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(LDO9, 0x45, 0, 0x47, 0, 0x54, 0x7F, 0x60,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(LDO10, 0x45, 1, 0x47, 1, 0x55, 0x7F, 0x61,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(LDORTC1, 0x45, 4, 0x00, 0, 0x56, 0x7F, 0x00,
+                       1700000, 3500000, 25000, 0x48, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+
+       RICOH619_REG(LDORTC2, 0x45, 5, 0x00, 0, 0x57, 0x7F, 0x00,
+                       900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+                       0x00, 0, 0x00, 0),
+};
+static inline struct ricoh619_regulator *find_regulator_info(int id)
+{
+       struct ricoh619_regulator *ri;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ricoh619_regulator); i++) {
+               ri = &ricoh619_regulator[i];
+               if (ri->desc.id == id)
+                       return ri;
+       }
+       return NULL;
+}
+
+static int ricoh619_regulator_preinit(struct device *parent,
+               struct ricoh619_regulator *ri,
+               struct ricoh619_regulator_platform_data *ricoh619_pdata)
+{
+       int ret = 0;
+
+       if (!ricoh619_pdata->init_apply)
+               return 0;
+/*
+       if (ricoh619_pdata->init_uV >= 0) {
+               ret = __ricoh619_set_voltage(parent, ri,
+                               ricoh619_pdata->init_uV,
+                               ricoh619_pdata->init_uV, 0);
+               if (ret < 0) {
+                       dev_err(ri->dev, "Not able to initialize voltage %d "
+                               "for rail %d err %d\n", ricoh619_pdata->init_uV,
+                               ri->desc.id, ret);
+                       return ret;
+               }
+       }
+*/
+       if (ricoh619_pdata->init_enable)
+               ret = ricoh619_set_bits(parent, ri->reg_en_reg,
+                                                       (1 << ri->en_bit));
+       else
+               ret = ricoh619_clr_bits(parent, ri->reg_en_reg,
+                                                       (1 << ri->en_bit));
+       if (ret < 0)
+               dev_err(ri->dev, "Not able to %s rail %d err %d\n",
+                       (ricoh619_pdata->init_enable) ? "enable" : "disable",
+                       ri->desc.id, ret);
+
+       return ret;
+}
+
+static inline int ricoh619_cache_regulator_register(struct device *parent,
+       struct ricoh619_regulator *ri)
+{
+       ri->vout_reg_cache = 0;
+       return ricoh619_read(parent, ri->vout_reg, &ri->vout_reg_cache);
+}
+
+static int __devinit ricoh619_regulator_probe(struct platform_device *pdev)
+{
+       struct ricoh619_regulator *ri = NULL;
+       struct regulator_dev *rdev;
+       struct ricoh619_regulator_platform_data *tps_pdata;
+       int id = pdev->id;
+       int err;
+
+       ri = find_regulator_info(id);
+       if (ri == NULL) {
+               dev_err(&pdev->dev, "invalid regulator ID specified\n");
+               return -EINVAL;
+       }
+       tps_pdata = pdev->dev.platform_data;
+       ri->dev = &pdev->dev;
+/*
+       err = ricoh619_cache_regulator_register(pdev->dev.parent, ri);
+       if (err) {
+               dev_err(&pdev->dev, "Fail in caching register\n");
+               return err;
+       }
+
+       err = ricoh619_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
+       if (err) {
+               dev_err(&pdev->dev, "Fail in pre-initialisation\n");
+               return err;
+       }
+       */
+       rdev = regulator_register(&ri->desc, &pdev->dev,
+                               &tps_pdata->regulator, ri);
+       if (IS_ERR_OR_NULL(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 ricoh619_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+       return 0;
+}
+
+static struct platform_driver ricoh619_regulator_driver = {
+       .driver = {
+               .name   = "ricoh619-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ricoh619_regulator_probe,
+       .remove         = __devexit_p(ricoh619_regulator_remove),
+};
+
+static int __init ricoh619_regulator_init(void)
+{
+
+       return platform_driver_register(&ricoh619_regulator_driver);
+}
+subsys_initcall_sync(ricoh619_regulator_init);
+
+static void __exit ricoh619_regulator_exit(void)
+{
+       platform_driver_unregister(&ricoh619_regulator_driver);
+}
+module_exit(ricoh619_regulator_exit);
+
+MODULE_DESCRIPTION("RICOH619 regulator driver");
+MODULE_ALIAS("platform:ricoh619-regulator");
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
index 62424f04a6c24d6d07cc832d2498c0928a049828..bf69ac4bdb814d90bfc73c22c0f6b219e9798cf8 100644 (file)
@@ -1121,5 +1121,15 @@ config  RK808_RTC
        depends on MFD_RK808
        help
                enable rk808 rtc for system
+               
+config RTC_DRV_RC5T619
+       tristate "RICOH RC5T619 PMU RTC driver"
+       depends on MFD_RICOH619
+       default n
+       help
+         If you say yes here you get support for the RICOH RC5T619 RTC module.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rc5t619.
 
 endif # RTC_CLASS
index e429fff538ec244214eaf6e5f76492fa17ba7aa4..936824da423b3b5f1e52faef296ddaebf5cb1602 100644 (file)
@@ -117,3 +117,4 @@ obj-$(CONFIG_RTC_HYM8563)   += rtc-HYM8563.o
 obj-$(CONFIG_RTC_M41T66)       += rtc-m41t66.o
 obj-$(CONFIG_TPS65910_RTC)  += rtc-tps65910.o
 obj-$(CONFIG_RK808_RTC)  += rtc-rk808.o
+obj-$(CONFIG_RTC_DRV_RC5T619)  += rtc-ricoh619.o
diff --git a/drivers/rtc/rtc-ricoh619.c b/drivers/rtc/rtc-ricoh619.c
new file mode 100644 (file)
index 0000000..cae88e1
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * drivers/rtc/rtc-ricoh619.c
+ *
+ * Real time clock driver for RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *  Copyright (C) 2011 NVIDIA Corporation  
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * this program is distributed in the hope that it will be useful, but without
+ * any warranty; without even the implied warranty of merchantability or
+ * fitness for a particular purpose.  see the gnu general public license for
+ * more details.
+ *
+ * you should have received a copy of the gnu general public license
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.  
+ *
+ */
+
+/* #define debug               1 */
+/* #define verbose_debug       1 */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/rtc/rtc-ricoh619.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+struct ricoh619_rtc {
+       unsigned long           epoch_start;
+       int                     irq;
+       struct rtc_device       *rtc;
+       bool                    irq_en;
+};
+
+static int ricoh619_read_regs(struct device *dev, int reg, int len,
+       uint8_t *val)
+{
+       int ret;
+
+       ret = ricoh619_bulk_reads(dev->parent, reg, len, val);
+       if (ret < 0) {
+               dev_err(dev->parent, "\n %s failed reading from 0x%02x\n",
+                       __func__, reg);
+               WARN_ON(1);
+       }
+       return ret;
+}
+
+static int ricoh619_write_regs(struct device *dev, int reg, int len,
+       uint8_t *val)
+{
+       int ret;
+       ret = ricoh619_bulk_writes(dev->parent, reg, len, val);
+       if (ret < 0) {
+               dev_err(dev->parent, "\n %s failed writing\n", __func__);
+               WARN_ON(1);
+       }
+
+       return ret;
+}
+
+static int ricoh619_rtc_valid_tm(struct device *dev, struct rtc_time *tm)
+{
+       if (tm->tm_year >= (rtc_year_offset + 99)
+               || tm->tm_mon > 12
+               || tm->tm_mday < 1
+               || tm->tm_mday > rtc_month_days(tm->tm_mon,
+                       tm->tm_year + os_ref_year)
+               || tm->tm_hour >= 24
+               || tm->tm_min >= 60
+               || tm->tm_sec >= 60) {
+               dev_err(dev->parent, "\n returning error due to time"
+               "%d/%d/%d %d:%d:%d", tm->tm_mon, tm->tm_mday,
+               tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static u8 dec2bcd(u8 dec)
+{
+       return ((dec/10)<<4)+(dec%10);
+}
+
+static u8 bcd2dec(u8 bcd)
+{
+       return (bcd >> 4)*10+(bcd & 0xf);
+}
+
+static void convert_bcd_to_decimal(u8 *buf, u8 len)
+{
+       int i = 0;
+       for (i = 0; i < len; i++)
+               buf[i] = bcd2dec(buf[i]);
+}
+
+static void convert_decimal_to_bcd(u8 *buf, u8 len)
+{
+       int i = 0;
+       for (i = 0; i < len; i++)
+               buf[i] = dec2bcd(buf[i]);
+}
+
+static void print_time(struct device *dev, struct rtc_time *tm)
+{
+       dev_info(dev, "rtc-time : %d/%d/%d %d:%d\n",
+               (tm->tm_mon + 1), tm->tm_mday, (tm->tm_year + os_ref_year),
+               tm->tm_hour, tm->tm_min);
+}
+
+static int ricoh619_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       u8 buff[7];
+       int err;
+       err = ricoh619_read_regs(dev, rtc_seconds_reg, sizeof(buff), buff);
+       if (err < 0) {
+               dev_err(dev, "\n %s :: failed to read time\n", __FILE__);
+               return err;
+       }
+       convert_bcd_to_decimal(buff, sizeof(buff));
+       tm->tm_sec  = buff[0];
+       tm->tm_min  = buff[1];
+       tm->tm_hour = buff[2];
+       tm->tm_wday = buff[3];
+       tm->tm_mday = buff[4];
+       tm->tm_mon  = buff[5] - 1;
+       tm->tm_year = buff[6] + rtc_year_offset;
+//     print_time(dev, tm);
+       return ricoh619_rtc_valid_tm(dev, tm);
+}
+
+static int ricoh619_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       u8 buff[7];
+       int err;
+
+//     print_time(dev, tm);
+       buff[0] = tm->tm_sec;
+       buff[1] = tm->tm_min;
+       buff[2] = tm->tm_hour;
+       buff[3] = tm->tm_wday;
+       buff[4] = tm->tm_mday;
+       buff[5] = tm->tm_mon + 1;
+       buff[6] = tm->tm_year - rtc_year_offset;
+
+       convert_decimal_to_bcd(buff, sizeof(buff));
+       err = ricoh619_write_regs(dev, rtc_seconds_reg, sizeof(buff), buff);
+       if (err < 0) {
+               dev_err(dev->parent, "\n failed to program new time\n");
+               return err;
+       }
+
+       return 0;
+}
+static int ricoh619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm);
+
+static int ricoh619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct ricoh619_rtc *rtc = dev_get_drvdata(dev);
+       unsigned long seconds;
+       u8 buff[6];
+       int err;
+       struct rtc_time tm;
+
+       if (rtc->irq == -1)
+               return -EIO;
+
+       rtc_tm_to_time(&alrm->time, &seconds);
+       err = ricoh619_rtc_read_time(dev, &tm);
+       if (err) {
+               dev_err(dev, "\n failed to read time\n");
+               return err;
+       }
+       rtc_tm_to_time(&tm, &rtc->epoch_start);
+
+       dev_info(dev->parent, "\n setting alarm to requested time::\n");
+//     print_time(dev->parent, &alrm->time);
+
+       if (WARN_ON(alrm->enabled && (seconds < rtc->epoch_start))) {
+               dev_err(dev->parent, "\n can't set alarm to requested time\n");
+               return -EINVAL;
+       }
+
+       if (alrm->enabled && !rtc->irq_en)
+               rtc->irq_en = true;
+       else if (!alrm->enabled && rtc->irq_en)
+               rtc->irq_en = false;
+
+       buff[0] = alrm->time.tm_sec;
+       buff[1] = alrm->time.tm_min;
+       buff[2] = alrm->time.tm_hour;
+       buff[3] = alrm->time.tm_mday;
+       buff[4] = alrm->time.tm_mon + 1;
+       buff[5] = alrm->time.tm_year - rtc_year_offset;
+       convert_decimal_to_bcd(buff, sizeof(buff));
+       buff[3] |= 0x80;        /* set DAL_EXT */
+       err = ricoh619_write_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff);
+       if (err) {
+               dev_err(dev->parent, "\n unable to set alarm\n");
+               return -EBUSY;
+       }
+
+       err = ricoh619_read_regs(dev, rtc_ctrl2, 1, buff);
+       if (err) {
+               dev_err(dev->parent, "unable to read rtc_ctrl2 reg\n");
+               return -EBUSY;
+       }
+
+       buff[1] = buff[0] & ~0x81; /* to clear alarm-D flag, and set adjustment parameter */
+       buff[0] = 0x60; /* to enable alarm_d and 24-hour format */
+       err = ricoh619_write_regs(dev, rtc_ctrl1, 2, buff);
+       if (err) {
+               dev_err(dev, "failed programming rtc ctrl regs\n");
+               return -EBUSY;
+       }
+return err;
+}
+
+static int ricoh619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       u8 buff[6];
+       int err;
+
+       err = ricoh619_read_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff);
+       if (err)
+               return err;
+       buff[3] &= ~0x80;       /* clear DAL_EXT */
+       convert_bcd_to_decimal(buff, sizeof(buff));
+
+       alrm->time.tm_sec  = buff[0];
+       alrm->time.tm_min  = buff[1];
+       alrm->time.tm_hour = buff[2];
+       alrm->time.tm_mday = buff[3];
+       alrm->time.tm_mon  = buff[4] - 1;
+       alrm->time.tm_year = buff[5] + rtc_year_offset;
+
+//     dev_info(dev->parent, "\n getting alarm time::\n");
+//     print_time(dev, &alrm->time);
+
+       return 0;
+}
+
+static const struct rtc_class_ops ricoh619_rtc_ops = {
+       .read_time      = ricoh619_rtc_read_time,
+       .set_time       = ricoh619_rtc_set_time,
+       .set_alarm      = ricoh619_rtc_set_alarm,
+       .read_alarm     = ricoh619_rtc_read_alarm,
+};
+
+static irqreturn_t ricoh619_rtc_irq(int irq, void *data)
+{
+       struct device *dev = data;
+       struct ricoh619_rtc *rtc = dev_get_drvdata(dev);
+       u8 reg;
+       int err;
+
+       /* clear alarm-D status bits.*/
+       err = ricoh619_read_regs(dev, rtc_ctrl2, 1, &reg);
+       if (err) {
+               dev_err(dev->parent, "unable to read rtc_ctrl2 reg\n");
+       }
+       reg &= ~0x81;   /* to clear alarm-D flag, and set adjustment parameter */
+       err = ricoh619_write_regs(dev, rtc_ctrl2, 1, &reg);
+       if (err) {
+               dev_err(dev->parent, "unable to program rtc_status reg\n");
+       }
+
+       rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static int __devinit ricoh619_rtc_probe(struct platform_device *pdev)
+{
+       struct ricoh619_rtc_platform_data *pdata = pdev->dev.platform_data;
+       struct ricoh619_rtc *rtc;
+       struct rtc_time tm;
+       int err;
+       u8 reg;
+       rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+//     printk("%s,line=%d\n", __func__,__LINE__);      
+
+       if (!rtc)
+               return -ENOMEM;
+
+       rtc->irq = -1;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform_data specified\n");
+               return -EINVAL;
+       }
+
+       if (pdata->irq < 0)
+               dev_err(&pdev->dev, "\n no irq specified, wakeup is disabled\n");
+
+       dev_set_drvdata(&pdev->dev, rtc);
+       device_init_wakeup(&pdev->dev, 1);
+       rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+                                      &ricoh619_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc->rtc)) {
+               err = PTR_ERR(rtc->rtc);
+               goto fail;
+       }
+
+       reg = 0x20; /* to clear power-on-reset flag */ 
+       err = ricoh619_write_regs(&pdev->dev, rtc_ctrl2, 1, &reg);
+       if (err) {
+               dev_err(&pdev->dev, "failed rtc setup\n");
+               return -EBUSY;
+       }
+
+       reg = 0x60; /* to enable alarm_d and 24-hour format */
+       err = ricoh619_write_regs(&pdev->dev, rtc_ctrl1, 1, &reg);
+       if (err) {
+               dev_err(&pdev->dev, "failed rtc setup\n");
+               return -EBUSY;
+       }
+
+       reg =  0; /* clearing RTC Adjust register */
+       err = ricoh619_write_regs(&pdev->dev, rtc_adjust, 1, &reg);
+       if (err) {
+               dev_err(&pdev->dev, "unable to program rtc_adjust reg\n");
+               return -EBUSY;
+       }
+
+       err = ricoh619_rtc_read_time(&pdev->dev, &tm);
+       if (err) {
+               dev_err(&pdev->dev, "\n failed to read time\n");
+               return err;
+       }
+       if (ricoh619_rtc_valid_tm(&pdev->dev, &tm)) {
+               if (pdata->time.tm_year < 2000 || pdata->time.tm_year > 2100) {
+                       memset(&pdata->time, 0, sizeof(pdata->time));
+                       pdata->time.tm_year = rtc_year_offset;
+                       pdata->time.tm_mday = 1;
+               } else
+               pdata->time.tm_year -= os_ref_year;
+               err = ricoh619_rtc_set_time(&pdev->dev, &pdata->time);
+               if (err) {
+                       dev_err(&pdev->dev, "\n failed to set time\n");
+                       return err;
+               }
+       }
+       if (pdata && (pdata->irq >= 0)) {
+               rtc->irq = pdata->irq + RICOH619_IRQ_DALE;
+               err = request_threaded_irq(rtc->irq, NULL, ricoh619_rtc_irq,
+                                       IRQF_ONESHOT, "rtc_ricoh619",
+                                       &pdev->dev);
+               if (err) {
+                       dev_err(&pdev->dev, "request IRQ:%d fail\n", rtc->irq);
+                       rtc->irq = -1;
+               } else {
+                       device_init_wakeup(&pdev->dev, 1);
+                       enable_irq_wake(rtc->irq);
+               }
+       }
+       return 0;
+
+fail:
+       if (!IS_ERR_OR_NULL(rtc->rtc))
+               rtc_device_unregister(rtc->rtc);
+       kfree(rtc);
+       return err;
+}
+
+static int __devexit ricoh619_rtc_remove(struct platform_device *pdev)
+{
+       struct ricoh619_rtc *rtc = dev_get_drvdata(&pdev->dev);
+
+       if (rtc->irq != -1)
+               free_irq(rtc->irq, rtc);
+       rtc_device_unregister(rtc->rtc);
+       kfree(rtc);
+       return 0;
+}
+
+static struct platform_driver ricoh619_rtc_driver = {
+       .driver = {
+               .name   = "rtc_ricoh619",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = ricoh619_rtc_probe,
+       .remove = __devexit_p(ricoh619_rtc_remove),
+};
+
+static int __init ricoh619_rtc_init(void)
+{
+       return platform_driver_register(&ricoh619_rtc_driver);
+}
+subsys_initcall_sync(ricoh619_rtc_init);
+
+static void __exit ricoh619_rtc_exit(void)
+{
+       platform_driver_unregister(&ricoh619_rtc_driver);
+}
+module_exit(ricoh619_rtc_exit);
+
+MODULE_DESCRIPTION("RICOH RICOH619 RTC driver");
+MODULE_ALIAS("platform:rtc_ricoh619");
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/mfd/ricoh619.h b/include/linux/mfd/ricoh619.h
new file mode 100644 (file)
index 0000000..627a607
--- /dev/null
@@ -0,0 +1,354 @@
+/* 
+ * include/linux/mfd/ricoh619.h
+ *
+ * Core driver interface to access RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *     Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_RICOH619_H
+#define __LINUX_MFD_RICOH619_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+/* Maximum number of main interrupts */
+#define MAX_INTERRUPT_MASKS    13
+#define MAX_MAIN_INTERRUPT     7
+#define MAX_GPEDGE_REG         2
+
+/* Power control register */
+#define RICOH619_PWR_WD                        0x0B
+#define RICOH619_PWR_WD_COUNT          0x0C
+#define RICOH619_PWR_FUNC              0x0D
+#define RICOH619_PWR_SLP_CNT           0x0E
+#define RICOH619_PWR_REP_CNT           0x0F
+#define RICOH619_PWR_ON_TIMSET         0x10
+#define RICOH619_PWR_NOE_TIMSET                0x11
+#define RICOH619_PWR_IRSEL             0x15
+
+/* Interrupt enable register */
+#define RICOH619_INT_EN_SYS            0x12
+#define RICOH619_INT_EN_DCDC           0x40
+#define RICOH619_INT_EN_RTC            0xAE
+#define RICOH619_INT_EN_ADC1           0x88
+#define RICOH619_INT_EN_ADC2           0x89
+#define RICOH619_INT_EN_ADC3           0x8A
+#define RICOH619_INT_EN_GPIO           0x94
+#define RICOH619_INT_EN_GPIO2          0x94 // dummy
+#define RICOH619_INT_MSK_CHGCTR                0xBE
+#define RICOH619_INT_MSK_CHGSTS1       0xBF
+#define RICOH619_INT_MSK_CHGSTS2       0xC0
+#define RICOH619_INT_MSK_CHGERR                0xC1
+#define RICOH619_INT_MSK_CHGEXTIF      0xD1
+
+/* Interrupt select register */
+#define RICOH619_PWR_IRSEL                     0x15
+#define RICOH619_CHG_CTRL_DETMOD1      0xCA
+#define RICOH619_CHG_CTRL_DETMOD2      0xCB
+#define RICOH619_CHG_STAT_DETMOD1      0xCC
+#define RICOH619_CHG_STAT_DETMOD2      0xCD
+#define RICOH619_CHG_STAT_DETMOD3      0xCE
+
+
+/* interrupt status registers (monitor regs)*/
+#define RICOH619_INTC_INTPOL           0x9C
+#define RICOH619_INTC_INTEN            0x9D
+#define RICOH619_INTC_INTMON           0x9E
+
+#define RICOH619_INT_MON_SYS           0x14
+#define RICOH619_INT_MON_DCDC          0x42
+#define RICOH619_INT_MON_RTC           0xAF
+
+#define RICOH619_INT_MON_CHGCTR                0xC6
+#define RICOH619_INT_MON_CHGSTS1       0xC7
+#define RICOH619_INT_MON_CHGSTS2       0xC8
+#define RICOH619_INT_MON_CHGERR                0xC9
+#define RICOH619_INT_MON_CHGEXTIF      0xD3
+
+/* interrupt clearing registers */
+#define RICOH619_INT_IR_SYS            0x13
+#define RICOH619_INT_IR_DCDC           0x41
+#define RICOH619_INT_IR_RTC            0xAF
+#define RICOH619_INT_IR_ADCL           0x8C
+#define RICOH619_INT_IR_ADCH           0x8D
+#define RICOH619_INT_IR_ADCEND         0x8E
+#define RICOH619_INT_IR_GPIOR          0x95
+#define RICOH619_INT_IR_GPIOF          0x96
+#define RICOH619_INT_IR_CHGCTR         0xC2
+#define RICOH619_INT_IR_CHGSTS1                0xC3
+#define RICOH619_INT_IR_CHGSTS2                0xC4
+#define RICOH619_INT_IR_CHGERR         0xC5
+#define RICOH619_INT_IR_CHGEXTIF       0xD2
+
+/* GPIO register base address */
+#define RICOH619_GPIO_IOSEL            0x90
+#define RICOH619_GPIO_IOOUT            0x91
+#define RICOH619_GPIO_GPEDGE1          0x92
+#define RICOH619_GPIO_GPEDGE2          0x93
+//#define RICOH619_GPIO_EN_GPIR                0x94
+//#define RICOH619_GPIO_IR_GPR         0x95
+//#define RICOH619_GPIO_IR_GPF         0x96
+#define RICOH619_GPIO_MON_IOIN         0x97
+#define RICOH619_GPIO_LED_FUNC         0x98
+
+#define RICOH619_REG_BANKSEL           0xFF
+
+/* Charger Control register */
+#define RICOH619_CHG_CTL1              0xB3
+
+/* ADC Control register */
+#define RICOH619_ADC_CNT1              0x64
+#define RICOH619_ADC_CNT2              0x65
+#define RICOH619_ADC_CNT3              0x66
+#define RICOH619_ADC_VADP_THL          0x7C
+#define RICOH619_ADC_VSYS_THL          0x80
+
+#define        RICOH619_FG_CTRL                0xE0
+#define        RICOH619_PSWR                   0x07
+
+/* RICOH619 IRQ definitions */
+enum {
+       RICOH619_IRQ_POWER_ON,
+       RICOH619_IRQ_EXTIN,
+       RICOH619_IRQ_PRE_VINDT,
+       RICOH619_IRQ_PREOT,
+       RICOH619_IRQ_POWER_OFF,
+       RICOH619_IRQ_NOE_OFF,
+       RICOH619_IRQ_WD,
+       RICOH619_IRQ_CLK_STP,
+
+       RICOH619_IRQ_DC1LIM,
+       RICOH619_IRQ_DC2LIM,
+       RICOH619_IRQ_DC3LIM,
+       RICOH619_IRQ_DC4LIM,
+       RICOH619_IRQ_DC5LIM,
+
+       RICOH619_IRQ_ILIMLIR,
+       RICOH619_IRQ_VBATLIR,
+       RICOH619_IRQ_VADPLIR,
+       RICOH619_IRQ_VUSBLIR,
+       RICOH619_IRQ_VSYSLIR,
+       RICOH619_IRQ_VTHMLIR,
+       RICOH619_IRQ_AIN1LIR,
+       RICOH619_IRQ_AIN0LIR,
+       
+       RICOH619_IRQ_ILIMHIR,
+       RICOH619_IRQ_VBATHIR,
+       RICOH619_IRQ_VADPHIR,
+       RICOH619_IRQ_VUSBHIR,
+       RICOH619_IRQ_VSYSHIR,
+       RICOH619_IRQ_VTHMHIR,
+       RICOH619_IRQ_AIN1HIR,
+       RICOH619_IRQ_AIN0HIR,
+
+       RICOH619_IRQ_ADC_ENDIR,
+
+       RICOH619_IRQ_GPIO0,
+       RICOH619_IRQ_GPIO1,
+       RICOH619_IRQ_GPIO2,
+       RICOH619_IRQ_GPIO3,
+       RICOH619_IRQ_GPIO4,
+
+       RICOH619_IRQ_CTC,
+       RICOH619_IRQ_DALE,
+
+       RICOH619_IRQ_FVADPDETSINT,
+       RICOH619_IRQ_FVUSBDETSINT,
+       RICOH619_IRQ_FVADPLVSINT,
+       RICOH619_IRQ_FVUSBLVSINT,
+       RICOH619_IRQ_FWVADPSINT,
+       RICOH619_IRQ_FWVUSBSINT,
+
+       RICOH619_IRQ_FONCHGINT,
+       RICOH619_IRQ_FCHGCMPINT,
+       RICOH619_IRQ_FBATOPENINT,
+       RICOH619_IRQ_FSLPMODEINT,
+       RICOH619_IRQ_FBTEMPJTA1INT,
+       RICOH619_IRQ_FBTEMPJTA2INT,
+       RICOH619_IRQ_FBTEMPJTA3INT,
+       RICOH619_IRQ_FBTEMPJTA4INT,
+
+       RICOH619_IRQ_FCURTERMINT,
+       RICOH619_IRQ_FVOLTERMINT,
+       RICOH619_IRQ_FICRVSINT,
+       RICOH619_IRQ_FPOOR_CHGCURINT,
+       RICOH619_IRQ_FOSCFDETINT1,
+       RICOH619_IRQ_FOSCFDETINT2,
+       RICOH619_IRQ_FOSCFDETINT3,
+       RICOH619_IRQ_FOSCMDETINT,
+
+       RICOH619_IRQ_FDIEOFFINT,
+       RICOH619_IRQ_FDIEERRINT,
+       RICOH619_IRQ_FBTEMPERRINT,
+       RICOH619_IRQ_FVBATOVINT,
+       RICOH619_IRQ_FTTIMOVINT,
+       RICOH619_IRQ_FRTIMOVINT,
+       RICOH619_IRQ_FVADPOVSINT,
+       RICOH619_IRQ_FVUSBOVSINT,
+
+       RICOH619_IRQ_FGCDET,
+       RICOH619_IRQ_FPCDET,
+       RICOH619_IRQ_FWARN_ADP,
+
+       /* Should be last entry */
+       RICOH619_NR_IRQS,
+};
+
+/* Ricoh619 gpio definitions */
+enum {
+       RICOH619_GPIO0,
+       RICOH619_GPIO1,
+       RICOH619_GPIO2,
+       RICOH619_GPIO3,
+       RICOH619_GPIO4,
+
+       RICOH619_NR_GPIO,
+};
+
+enum ricoh619_sleep_control_id {
+       RICOH619_DS_DC1,
+       RICOH619_DS_DC2,
+       RICOH619_DS_DC3,
+       RICOH619_DS_DC4,
+       RICOH619_DS_DC5,
+       RICOH619_DS_LDO1,
+       RICOH619_DS_LDO2,
+       RICOH619_DS_LDO3,
+       RICOH619_DS_LDO4,
+       RICOH619_DS_LDO5,
+       RICOH619_DS_LDO6,
+       RICOH619_DS_LDO7,
+       RICOH619_DS_LDO8,
+       RICOH619_DS_LDO9,
+       RICOH619_DS_LDO10,
+       RICOH619_DS_LDORTC1,
+       RICOH619_DS_LDORTC2,
+       RICOH619_DS_PSO0,
+       RICOH619_DS_PSO1,
+       RICOH619_DS_PSO2,
+       RICOH619_DS_PSO3,
+       RICOH619_DS_PSO4,
+};
+
+
+struct ricoh619_subdev_info {
+       int             id;
+       const char      *name;
+       void            *platform_data;
+};
+
+/*
+struct ricoh619_rtc_platform_data {
+       int irq;
+       struct rtc_time time;
+};
+*/
+
+struct ricoh619_gpio_init_data {
+       unsigned output_mode_en:1;      /* Enable output mode during init */
+       unsigned output_val:1;          /* Output value if it is in output mode */
+       unsigned init_apply:1;          /* Apply init data on configuring gpios*/
+       unsigned led_mode:1;            /* Select LED mode during init */
+       unsigned led_func:1;            /* Set LED function if LED mode is 1 */
+};
+
+struct ricoh619 {
+       struct device           *dev;
+       struct i2c_client       *client;
+       struct mutex            io_lock;
+       int                     gpio_base;
+       struct gpio_chip        gpio_chip;
+       int                     irq_base;
+//     struct irq_chip         irq_chip;
+       int                     chip_irq;
+       struct mutex            irq_lock;
+       unsigned long           group_irq_en[MAX_MAIN_INTERRUPT];
+
+       /* For main interrupt bits in INTC */
+       u8                      intc_inten_cache;
+       u8                      intc_inten_reg;
+
+       /* For group interrupt bits and address */
+       u8                      irq_en_cache[MAX_INTERRUPT_MASKS];
+       u8                      irq_en_reg[MAX_INTERRUPT_MASKS];
+
+       /* For gpio edge */
+       u8                      gpedge_cache[MAX_GPEDGE_REG];
+       u8                      gpedge_reg[MAX_GPEDGE_REG];
+
+       int                     bank_num;
+};
+
+struct ricoh619_platform_data {
+       int             num_subdevs;
+       struct  ricoh619_subdev_info *subdevs;
+       int (*init_port)(int irq_num); // Init GPIO for IRQ pin
+       int             gpio_base;
+       int             irq_base;
+       struct ricoh619_gpio_init_data *gpio_init_data;
+       int num_gpioinit_data;
+       bool enable_shutdown_pin;
+       int (*pre_init)(struct ricoh619 *ricoh619);
+       int (*post_init)(struct ricoh619 *ricoh619);
+};
+
+/* ==================================== */
+/* RICOH619 Power_Key device data      */
+/* ==================================== */
+struct ricoh619_pwrkey_platform_data {
+       int irq;
+       unsigned long delay_ms;
+};
+extern int pwrkey_wakeup;
+extern struct ricoh619 *g_ricoh619;
+/* ==================================== */
+/* RICOH619 battery device data        */
+/* ==================================== */
+extern int g_soc;
+extern int g_fg_on_mode;
+
+extern int ricoh619_read(struct device *dev, uint8_t reg, uint8_t *val);
+extern int ricoh619_read_bank1(struct device *dev, uint8_t reg, uint8_t *val);
+extern int ricoh619_bulk_reads(struct device *dev, u8 reg, u8 count,
+                                                               uint8_t *val);
+extern int ricoh619_bulk_reads_bank1(struct device *dev, u8 reg, u8 count,
+                                                               uint8_t *val);
+extern int ricoh619_write(struct device *dev, u8 reg, uint8_t val);
+extern int ricoh619_write_bank1(struct device *dev, u8 reg, uint8_t val);
+extern int ricoh619_bulk_writes(struct device *dev, u8 reg, u8 count,
+                                                               uint8_t *val);
+extern int ricoh619_bulk_writes_bank1(struct device *dev, u8 reg, u8 count,
+                                                               uint8_t *val);
+extern int ricoh619_set_bits(struct device *dev, u8 reg, uint8_t bit_mask);
+extern int ricoh619_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask);
+extern int ricoh619_update(struct device *dev, u8 reg, uint8_t val,
+                                                               uint8_t mask);
+extern int ricoh619_update_bank1(struct device *dev, u8 reg, uint8_t val,
+                                                               uint8_t mask);
+extern int ricoh619_power_off(void);
+extern int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq, int irq_base);
+extern int ricoh619_irq_exit(struct ricoh619 *ricoh619);
+extern int ricoh619_power_off(void);
+
+#endif
diff --git a/include/linux/power/ricoh619_battery.h b/include/linux/power/ricoh619_battery.h
new file mode 100644 (file)
index 0000000..d930ff6
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * include/linux/power/ricoh619-battery.c
+ *
+ * RICOH RC5T619 Charger Driver
+ * 
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __LINUX_POWER_RICOH619_H_
+#define __LINUX_POWER_RICOH619_H_
+
+/* #include <linux/power_supply.h> */
+/* #include <linux/types.h> */
+
+#if 0
+#define RICOH_FG_DBG(fmt, args...) printk(KERN_DEBUG "RICOH_FG_DBG:\t"fmt, ##args)
+#else
+#define RICOH_FG_DBG(fmt, args...) {while(0);}
+#endif
+
+/* Defined buttery information */
+#define        ADC_VDD_MV      2800
+#define        MIN_VOLTAGE     3100
+#define        MAX_VOLTAGE     4200
+
+/* 619 Register information */
+/* bank 0 */
+#define PSWR_REG               0x07
+/* for ADC */
+#define        INTEN_REG               0x9D
+#define        EN_ADCIR3_REG           0x8A
+#define        ADCCNT3_REG             0x66
+#define        VBATDATAH_REG           0x6A
+#define        VBATDATAL_REG           0x6B
+
+#define CHGCTL1_REG            0xB3
+#define        REGISET1_REG    0xB6
+#define        REGISET2_REG    0xB7
+#define        CHGISET_REG             0xB8
+#define        BATSET2_REG             0xBB
+
+#define CHGSTATE_REG           0xBD
+
+#define        FG_CTRL_REG             0xE0
+#define        SOC_REG                 0xE1
+#define        RE_CAP_H_REG            0xE2
+#define        RE_CAP_L_REG            0xE3
+#define        FA_CAP_H_REG            0xE4
+#define        FA_CAP_L_REG            0xE5
+#define        TT_EMPTY_H_REG          0xE7
+#define        TT_EMPTY_L_REG          0xE8
+#define        TT_FULL_H_REG           0xE9
+#define        TT_FULL_L_REG           0xEA
+#define        VOLTAGE_1_REG           0xEB
+#define        VOLTAGE_2_REG           0xEC
+#define        TEMP_1_REG              0xED
+#define        TEMP_2_REG              0xEE
+
+#define        CC_CTRL_REG             0xEF
+#define        CC_SUMREG3_REG          0xF3
+#define        CC_SUMREG2_REG          0xF4
+#define        CC_SUMREG1_REG          0xF5
+#define        CC_SUMREG0_REG          0xF6
+#define        CC_AVERAGE1_REG         0xFB
+#define        CC_AVERAGE0_REG         0xFC
+
+/* bank 1 */
+/* Top address for battery initial setting */
+#define        BAT_INIT_TOP_REG        0xBC
+#define        BAT_REL_SEL_REG         0xDA
+/**************************/
+
+/* detailed status in CHGSTATE (0xBD) */
+enum ChargeState {
+       CHG_STATE_CHG_OFF = 0,
+       CHG_STATE_CHG_READY_VADP,
+       CHG_STATE_CHG_TRICKLE,
+       CHG_STATE_CHG_RAPID,
+       CHG_STATE_CHG_COMPLETE,
+       CHG_STATE_SUSPEND,
+       CHG_STATE_VCHG_OVER_VOL,
+       CHG_STATE_BAT_ERROR,
+       CHG_STATE_NO_BAT,
+       CHG_STATE_BAT_OVER_VOL,
+       CHG_STATE_BAT_TEMP_ERR,
+       CHG_STATE_DIE_ERR,
+       CHG_STATE_DIE_SHUTDOWN,
+       CHG_STATE_NO_BAT2,
+       CHG_STATE_CHG_READY_VUSB,
+};
+
+enum SupplyState {
+       SUPPLY_STATE_BAT = 0,
+       SUPPLY_STATE_ADP,
+       SUPPLY_STATE_USB,
+} ;
+
+struct ricoh619_battery_platform_data {
+       int     irq;
+       int     alarm_vol_mv;
+       int     multiple;
+       unsigned long   monitor_time;
+};
+
+extern struct ricoh619 *g_ricoh619;
+
+
+#endif
diff --git a/include/linux/power/ricoh61x_battery_init.h b/include/linux/power/ricoh61x_battery_init.h
new file mode 100644 (file)
index 0000000..d772d6f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * include/linux/power/ricoh61x_battery_init.h
+ *
+ * Battery initial parameter for RICOH RN5T618/619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+#ifndef __LINUX_POWER_RICOH61X_BATTERY_INIT_H
+#define __LINUX_POWER_RICOH61X_BATTERY_INIT_H
+
+
+uint8_t battery_init_para[32] = {
+        0x0B, 0x3F, 0x0B, 0xCB, 0x0B, 0xEE, 0x0C, 0x08, 0x0C, 0x1E, 0x0C, 0x38, 0x0C, 0x5B, 0x0C, 0x94,
+        0x0C, 0xC8, 0x0D, 0x08, 0x0D, 0x55, 0x0E, 0x14, 0x00, 0x39, 0x0F, 0xC8, 0x05, 0x2C, 0x22, 0x56
+//        0x0C, 0xC8, 0x0D, 0x08, 0x0D, 0x55, 0x0E, 0x14, 0x00, 0x3E, 0x0F, 0xC8, 0x05, 0x2C, 0x22, 0x56 //150ohme
+//        0x0C, 0xC8, 0x0D, 0x08, 0x0D, 0x55, 0x0E, 0x14, 0x00, 0x32, 0x0F, 0xC8, 0x05, 0x2C, 0x22, 0x56 //120ohme
+               //0x08, 0xa3, 0x0a, 0xf9, 0x0b, 0x4b, 0x0b, 0x74,
+               //0x0b, 0x94, 0x0b, 0xb5, 0x0b, 0xe6, 0x0c, 0x30,
+               //0x0c, 0x92, 0x0c, 0xf4, 0x0d, 0x6f, 0x08, 0xca,
+               //0x00, 0x36, 0x0f, 0xc8, 0x05, 0x2c, 0x22, 0x56
+};
+
+#endif
+
+/*
+<Other Parameter>
+nominal_capacity=3800
+cut-off_v=3400
+thermistor_b=3435
+board_impe=0
+bat_impe=0.1363
+load_c=768
+available_c=3604
+battery_v=3515
+MakingMode=Normal
+ChargeV=4.20V
+LoadMode=Resistor
+ */
+
diff --git a/include/linux/regulator/ricoh619-regulator.h b/include/linux/regulator/ricoh619-regulator.h
new file mode 100755 (executable)
index 0000000..96b4cee
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * linux/regulator/ricoh619-regulator.h
+ *
+ * Regulator driver for RICOH619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *     Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __LINUX_REGULATOR_RICOH619_H
+#define __LINUX_REGULATOR_RICOH619_H
+
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+
+#define ricoh619_rails(_name) "RICOH619_"#_name
+
+/* RICHOH Regulator IDs */
+enum regulator_id {
+       RICOH619_ID_DC1,
+       RICOH619_ID_DC2,        
+       RICOH619_ID_DC3,
+       RICOH619_ID_DC4,
+       RICOH619_ID_DC5,
+       RICOH619_ID_LDO1,
+       RICOH619_ID_LDO2,
+       RICOH619_ID_LDO3,
+       RICOH619_ID_LDO4,
+       RICOH619_ID_LDO5,
+       RICOH619_ID_LDO6,
+       RICOH619_ID_LDO7,
+       RICOH619_ID_LDO8,
+       RICOH619_ID_LDO9,
+       RICOH619_ID_LDO10,
+       RICOH619_ID_LDORTC1,
+       RICOH619_ID_LDORTC2,
+};
+
+struct ricoh619_regulator_platform_data {
+               struct regulator_init_data regulator;
+               int init_uV;
+               unsigned init_enable:1;
+               unsigned init_apply:1;
+               int sleep_uV;
+               int sleep_slots;
+               unsigned long ext_pwr_req;
+               unsigned long flags;
+};
+
+extern int ricoh619_regulator_enable_eco_mode(struct regulator_dev *rdev);
+extern int ricoh619_regulator_disable_eco_mode(struct regulator_dev *rdev);
+extern int ricoh619_regulator_enable_eco_slp_mode(struct regulator_dev *rdev);
+extern int ricoh619_regulator_disable_eco_slp_mode(struct regulator_dev *rdev);
+
+
+#endif
diff --git a/include/linux/rtc/rtc-ricoh619.h b/include/linux/rtc/rtc-ricoh619.h
new file mode 100755 (executable)
index 0000000..317e7ef
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * include/linux/rtc/rtc-ricoh619.h
+ *
+ * Real time clock driver for RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 RICOH COMPANY,LTD
+ *
+ * Based on code
+ *  Copyright (C) 2011 NVIDIA Corporation  
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * you should have received a copy of the gnu general public license
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.  
+ *
+ */
+#ifndef __LINUX_RTC_RICOH619_H_
+#define __LINUX_RTC_RICOH619_H_
+
+#include <linux/rtc.h>
+
+#define rtc_ctrl1              0xAE
+#define rtc_ctrl2              0xAF
+#define rtc_seconds_reg                0xA0
+#define rtc_alarm_y_sec                0xA8
+#define rtc_adjust             0xA7
+
+
+/*
+linux rtc driver refers 1900 as base year in many calculations.
+(e.g. refer drivers/rtc/rtc-lib.c)
+*/
+#define os_ref_year 1900
+
+/*
+       pmu rtc have only 2 nibbles to store year information, so using an
+       offset of 100 to set the base year as 2000 for our driver.
+*/
+#define rtc_year_offset 100
+
+
+
+struct ricoh619_rtc_platform_data {
+       int irq;
+       struct rtc_time time;
+};
+
+
+#endif