aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/ricoh619-battery.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/ricoh619-battery.c')
-rwxr-xr-xdrivers/power/ricoh619-battery.c6361
1 files changed, 6361 insertions, 0 deletions
diff --git a/drivers/power/ricoh619-battery.c b/drivers/power/ricoh619-battery.c
new file mode 100755
index 00000000..0185771e
--- /dev/null
+++ b/drivers/power/ricoh619-battery.c
@@ -0,0 +1,6361 @@
+/*
+ * drivers/power/ricoh619-battery.c
+ *
+ * Charger driver for RICOH R5T619 power management chip.
+ *
+ * Copyright (C) 2012-2014 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/>.
+ *
+ */
+#define RICOH61x_BATTERY_VERSION "RICOH61x_BATTERY_VERSION: 2014.02.21 V3.1.0.0-Solution1 2015/02/09"
+
+
+#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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/rtc.h>
+#include <asm-generic/rtc.h>
+
+#include <linux/power/ricoh619_standby.h>
+
+#include "../../../arch/arm/mach-mx6/ntx_hwconfig.h"
+extern volatile NTX_HWCONFIG *gptHWCFG;
+
+/* define for function */
+#define ENABLE_FUEL_GAUGE_FUNCTION
+#define ENABLE_LOW_BATTERY_DETECTION
+#define ENABLE_FACTORY_MODE
+#define DISABLE_CHARGER_TIMER
+/* #define ENABLE_FG_KEEP_ON_MODE */
+#define ENABLE_OCV_TABLE_CALIB
+/* #define ENABLE_MASKING_INTERRUPT_IN_SLEEP */
+
+#define ENABLE_BATTERY_TEMP_DETECTION
+#define LOW_BATTERY_TEMP_VOL 1824 // 0 degree 269.96K, 2.5V * 270K / (270K+100K)
+#define HIGH_BATTERY_TEMP_VOL 577 // 60 degree 30.546K, 2.5V * 30K / (30K+100K)
+
+#define _RICOH619_DEBUG_
+#define LTS_DEBUG
+//#define STANDBY_MODE_DEBUG
+//#define CHANGE_FL_MODE_DEBUG
+
+/* FG setting */
+#define RICOH61x_REL1_SEL_VALUE 64
+#define RICOH61x_REL2_SEL_VALUE 0
+
+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 delayed time */
+#define RICOH61x_MONITOR_START_TIME 15
+#define RICOH61x_FG_RESET_TIME 6
+#define RICOH61x_MAIN_START_TIME 2
+#define RICOH61x_FG_STABLE_TIME 120
+#define RICOH61x_DISP_CHG_UPDATE_TIME 10
+#define RICOH61x_DISPLAY_UPDATE_TIME 29
+#define RICOH61x_LOW_VOL_DOWN_TIME 60 //10
+#define RICOH61x_CHARGE_MONITOR_TIME 19
+#define RICOH61x_CHARGE_RESUME_TIME 1
+#define RICOH61x_CHARGE_CALC_TIME 1
+#define RICOH61x_JEITA_UPDATE_TIME 60
+#define RICOH61x_DELAY_TIME 40 /* 120 */
+/* define for FG parameter */
+#define RICOH61x_MAX_RESET_SOC_DIFF 5
+#define RICOH61x_GET_CHARGE_NUM 10
+#define RICOH61x_UPDATE_COUNT_DISP 4
+#define RICOH61x_UPDATE_COUNT_FULL 4
+#define RICOH61x_UPDATE_COUNT_FULL_RESET 4
+#define RICOH61x_CHARGE_UPDATE_TIME 3
+#define RE_CAP_GO_DOWN 10 /* 40 */
+#define RICOH61x_ENTER_LOW_VOL 70
+#define RICOH61x_TAH_SEL2 5
+#define RICOH61x_TAL_SEL2 6
+
+#define RICOH61x_OCV_OFFSET_BOUND 3
+#define RICOH61x_OCV_OFFSET_RATIO 2
+
+#define RICOH61x_ENTER_FULL_STATE_OCV 9
+#define RICOH61x_ENTER_FULL_STATE_DSOC 85 /* 90 */
+
+#define RICOH61x_FL_LEVEL_DEF 70 // 70%
+#define RICOH61x_FL_CURRENT_DEF 29593 // 29.593mA(70%)
+#define RICOH61x_IDLE_CURRENT_DEF 20000 // 20mA
+#define RICOH61x_SUS_CURRENT_DEF 3000 // 3mA
+#define RICOH61x_SUS_CURRENT_THRESH 20000 // 20mA
+#define RICOH61x_HIBER_CURRENT_DEF 800 // 0.8mA
+#define RICOH61x_FL_CURRENT_LIMIT 150000 // 150mA
+#define RICOH61x_SLEEP_CURRENT_LIMIT 50000 // 50mA
+
+#define ORIGINAL 0
+#define USING 1
+
+
+/* define for FG status */
+enum {
+ RICOH61x_SOCA_START,
+ RICOH61x_SOCA_UNSTABLE,
+ RICOH61x_SOCA_FG_RESET,
+ RICOH61x_SOCA_DISP,
+ RICOH61x_SOCA_STABLE,
+ RICOH61x_SOCA_ZERO,
+ RICOH61x_SOCA_FULL,
+ RICOH61x_SOCA_LOW_VOL,
+};
+
+/* table of dividing charge current */
+#define RICOH61x_IBAT_TABLE_NUM 16
+static int ibat_table[RICOH61x_IBAT_TABLE_NUM] /* 85% - 100% */
+ = {370, 348, 326, 304, 282, 260, 238, 216, 194, 172, 150, 128, 107, 87, 68, 50};
+
+#endif
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+#define LOW_BATTERY_DETECTION_TIME 0 //10
+#endif
+
+struct ricoh61x_soca_info {
+ int Rbat;
+ int n_cap;
+ int ocv_table_def[11];
+ int ocv_table[11];
+ int ocv_table_low[11];
+ uint8_t battery_init_para_original[32];
+ int soc; /* Latest FG SOC value */
+ int displayed_soc;
+ int suspend_soc;
+ int suspend_cc;
+ int suspend_rsoc;
+ bool suspend_full_flg;
+ 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 cc_cap_offset;
+ long sus_cc_cap_offset;
+ int last_soc;
+ int last_displayed_soc;
+ int last_cc_rrf0;
+ int last_cc_delta_cap;
+ long last_cc_delta_cap_mas;
+ long temp_cc_delta_cap_mas;
+ int temp_cc_delta_cap;
+ int ready_fg;
+ int reset_count;
+ int reset_soc[3];
+ int dischg_state;
+ int Vbat[RICOH61x_GET_CHARGE_NUM];
+ int Vsys[RICOH61x_GET_CHARGE_NUM];
+ int Ibat[RICOH61x_GET_CHARGE_NUM];
+ int Vbat_ave;
+ int Vbat_old;
+ int Vsys_ave;
+ int Ibat_ave;
+ int chg_count;
+ int full_reset_count;
+ int soc_full;
+ int fc_cap;
+ /* for LOW VOL state */
+ int hurry_up_flg;
+ int zero_flg;
+ int re_cap_old;
+
+ int cutoff_ocv;
+ int Rsys;
+ int target_vsys;
+ int target_ibat;
+ int jt_limit;
+ int OCV100_min;
+ int OCV100_max;
+ int R_low;
+ int rsoc_ready_flag;
+ int init_pswr;
+ int last_soc_full;
+ int rsoc_limit;
+ int critical_low_flag;
+
+ int store_fl_current;
+ int store_slp_state;
+ int store_sus_current;
+ int store_hiber_current;
+};
+
+static int critical_low_flag = 0;
+
+struct ricoh61x_battery_info {
+ struct device *dev;
+ struct power_supply battery;
+ struct delayed_work monitor_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
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+ struct delayed_work battery_temp_work;
+#endif
+ struct delayed_work charge_monitor_work;
+ struct delayed_work get_charge_work;
+ struct delayed_work jeita_work;
+
+ struct work_struct irq_work; /* for Charging & VADP/VUSB */
+
+ struct workqueue_struct *monitor_wqueue;
+ struct workqueue_struct *workqueue; /* for Charging & VUSB/VADP */
+
+#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 ricoh61x_soca_info *soca;
+ int first_pwon;
+ bool entry_factory_mode;
+ int ch_vfchg;
+ int ch_vrchg;
+ int ch_vbatovset;
+ int ch_ichg;
+ int ch_ilim_adp;
+ int ch_ilim_usb;
+ int ch_icchg;
+ int fg_target_vsys;
+ int fg_target_ibat;
+ int fg_poff_vbat;
+ int jt_en;
+ int jt_hw_sw;
+ int jt_temp_h;
+ int jt_temp_l;
+ int jt_vfchg_h;
+ int jt_vfchg_l;
+ int jt_ichg_h;
+ int jt_ichg_l;
+ bool suspend_state;
+ bool stop_disp;
+ unsigned long sleepEntryTime;
+ unsigned long sleepExitTime;
+
+ int num;
+ };
+
+int g_full_flag;
+int charger_irq;
+int g_soc;
+int g_fg_on_mode;
+
+#ifdef STANDBY_MODE_DEBUG
+int multiple_sleep_mode;
+#endif
+
+/*This is for full state*/
+static int BatteryTableFlageDef=0;
+static int BatteryTypeDef=0;
+static int Battery_Type(void)
+{
+ return BatteryTypeDef;
+}
+
+static int Battery_Table(void)
+{
+ return BatteryTableFlageDef;
+}
+
+static void ricoh61x_battery_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, monitor_work.work);
+
+// printk(KERN_INFO "PMU: %s\n", __func__);
+ power_supply_changed(&info->battery);
+ queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+ info->monitor_time);
+}
+
+#define RTC_SEC_REG 0xA0
+static void get_current_time(struct ricoh61x_battery_info *info,
+ unsigned long *seconds)
+{
+ struct rtc_time tm;
+ u8 buff[7];
+ int err;
+ int cent_flag;
+
+ /* get_rtc_time(&tm); */
+ err = ricoh61x_bulk_reads(info->dev->parent, RTC_SEC_REG, sizeof(buff), buff);
+ if (err < 0) {
+ dev_err(info->dev, "PMU: %s *** failed to read time *****\n", __func__);
+ return;
+ }
+ if (buff[5] & 0x80)
+ cent_flag = 1;
+ else
+ cent_flag = 0;
+
+ tm.tm_sec = bcd2bin(buff[0] & 0x7f);
+ tm.tm_min = bcd2bin(buff[1] & 0x7f);
+ tm.tm_hour = bcd2bin(buff[2] & 0x3f); /* 24h */
+ tm.tm_wday = bcd2bin(buff[3] & 0x07);
+ tm.tm_mday = bcd2bin(buff[4] & 0x3f);
+ tm.tm_mon = bcd2bin(buff[5] & 0x1f) - 1;/* back to system 0-11 */
+ tm.tm_year = bcd2bin(buff[6]) + 100 * cent_flag;
+
+ dev_dbg(info->dev, "rtc-time : Mon/ Day/ Year H:M:S\n");
+ dev_dbg(info->dev, " : %d/%d/%d %d:%d:%d\n",
+ (tm.tm_mon+1), tm.tm_mday, (tm.tm_year + 1900),
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ rtc_tm_to_time(&tm, seconds);
+}
+
+/**
+* Enable test register of Bank1
+*
+* info : battery info
+*
+* return value :
+* true : Removing Protect correctly
+* false : not Removing protect
+*/
+static bool Enable_Test_Register(struct ricoh61x_battery_info *info){
+ int ret;
+ uint8_t val = 0x01;
+ uint8_t val_backUp;
+ uint8_t val2;
+
+ //Remove protect of test register
+ ret = ricoh61x_write_bank1(info->dev->parent, BAT_TEST_EN_REG, 0xaa);
+ ret += ricoh61x_write_bank1(info->dev->parent, BAT_TEST_EN_REG, 0x55);
+ ret += ricoh61x_write_bank1(info->dev->parent, BAT_TEST_EN_REG, 0xaa);
+ ret += ricoh61x_write_bank1(info->dev->parent, BAT_TEST_EN_REG, 0x55);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing BAT_TEST_EN_REG\n");
+ return false;
+ }
+
+ //Check protect is removed or not
+ ret = ricoh61x_read_bank1(info->dev->parent, BAT_ADD1B2_REG, &val_backUp);
+ ret += ricoh61x_write_bank1(info->dev->parent, BAT_ADD1B2_REG, val);
+ ret += ricoh61x_read_bank1(info->dev->parent, BAT_ADD1B2_REG, &val2);
+ ret += ricoh61x_write_bank1(info->dev->parent, BAT_ADD1B2_REG, val_backUp);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing BAT_ADD1B2_REG\n");
+ return false;
+ }
+
+ if(val == val2){
+ return true;
+ } else {
+ return false;
+ }
+
+ return false;
+}
+
+/**
+* check can write correctly or not
+*
+* regAddr : register address
+* targetValue : target value for write
+* bank_num : bank number
+*
+* return : ture or false
+*/
+static bool write_and_check_read_back(struct ricoh61x_battery_info *info, u8 regAddr, uint8_t targetValue, int bank_num)
+{
+ int ret;
+ uint8_t val;
+
+ //Check protect is removed or not
+ if(bank_num == 0){
+ ret = ricoh61x_write(info->dev->parent, regAddr, targetValue);
+ ret += ricoh61x_read(info->dev->parent, regAddr, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing in 0x%d\n",regAddr);
+ return false;
+ }
+ } else {
+ ret = ricoh61x_write_bank1(info->dev->parent, regAddr, targetValue);
+ ret += ricoh61x_read_bank1(info->dev->parent, regAddr, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing in 0x%d\n",regAddr);
+ return false;
+ }
+ }
+
+ if(targetValue == val){
+ return true;
+ } else {
+ return false;
+ }
+}
+/**
+* get stored time from register
+* 0xB2 : bit 0 ~ 7
+* 0xB3 : bit 8 ~ 15
+* 0xDD : bit 16 ~ 23
+*
+* info : battery info
+*
+* return sored time unit is hour
+*/
+static unsigned long get_storedTime_from_register(struct ricoh61x_battery_info *info)
+{
+ unsigned long hour = 0;
+ uint8_t val;
+ int ret;
+
+ ret = ricoh61x_read_bank1(info->dev->parent, BAT_ADD1B2_REG, &val);
+ hour += val;
+ ret = ricoh61x_read_bank1(info->dev->parent, BAT_ADD1B3_REG, &val);
+ hour += val << 8;
+ ret = ricoh61x_read_bank1(info->dev->parent, BAT_ADD1DD_REG, &val);
+ hour += val << 16;
+
+
+ return hour;
+}
+
+
+/**
+* Set current RTC time to Register. unit is hour
+* 0xB2 : bit 0 ~ 7
+* 0xB3 : bit 8 ~ 15
+* 0xDD : bit 16 ~ 23
+*
+* info : battery info
+*
+* return
+*/
+static void set_current_time2register(struct ricoh61x_battery_info *info)
+{
+ unsigned long hour;
+ unsigned long seconds;
+ int loop_counter = 0;
+ bool canWriteFlag = true;
+ uint8_t val;
+
+ //
+ get_current_time(info, &seconds);
+ hour = seconds / 3600;
+ printk("PMU : %s : second is %lu, hour is %lu\n",__func__, seconds, hour);
+
+ do{
+ val = hour & 0xff;
+ canWriteFlag &= write_and_check_read_back(info, BAT_ADD1B2_REG, val, 1);
+ val = (hour >> 8) & 0xff;
+ canWriteFlag &= write_and_check_read_back(info, BAT_ADD1B3_REG, val, 1);
+ val = (hour >> 16) & 0xff;
+ canWriteFlag &= write_and_check_read_back(info, BAT_ADD1DD_REG, val, 1);
+
+ if(canWriteFlag != true){
+ Enable_Test_Register(info);
+ loop_counter++;
+ }
+
+ //read back
+ if(loop_counter > 5){
+ canWriteFlag = true;
+ }
+ }while(canWriteFlag == false);
+
+ return;
+}
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+static int measure_vbatt_FG(struct ricoh61x_battery_info *info, int *data);
+static int measure_Ibatt_FG(struct ricoh61x_battery_info *info, int *data);
+static int calc_capacity(struct ricoh61x_battery_info *info);
+static int calc_capacity_2(struct ricoh61x_battery_info *info);
+static int get_OCV_init_Data(struct ricoh61x_battery_info *info, int index, int table_num);
+static int get_OCV_voltage(struct ricoh61x_battery_info *info, int index, int table_num);
+static int get_check_fuel_gauge_reg(struct ricoh61x_battery_info *info,
+ int Reg_h, int Reg_l, int enable_bit);
+static int calc_capacity_in_period(struct ricoh61x_battery_info *info,
+ int *cc_cap, long *cc_cap_mas, bool *is_charging, int cc_rst);
+static int get_charge_priority(struct ricoh61x_battery_info *info, bool *data);
+static int set_charge_priority(struct ricoh61x_battery_info *info, bool *data);
+static int get_power_supply_status(struct ricoh61x_battery_info *info);
+static int get_power_supply_Android_status(struct ricoh61x_battery_info *info);
+static int measure_vsys_ADC(struct ricoh61x_battery_info *info, int *data);
+static int Calc_Linear_Interpolation(int x0, int y0, int x1, int y1, int y);
+static int get_battery_temp(struct ricoh61x_battery_info *info);
+static int get_battery_temp_2(struct ricoh61x_battery_info *info);
+static int check_jeita_status(struct ricoh61x_battery_info *info, bool *is_jeita_updated);
+static void ricoh61x_scaling_OCV_table(struct ricoh61x_battery_info *info, int cutoff_vol, int full_vol, int *start_per, int *end_per);
+static int ricoh61x_Check_OCV_Offset(struct ricoh61x_battery_info *info);
+static void mainFlowOfLowVoltage(struct ricoh61x_battery_info *info);
+static void initSettingOfLowVoltage(struct ricoh61x_battery_info *info);
+static int getCapFromOriTable(struct ricoh61x_battery_info *info, int voltage, int currentvalue, int resvalue);
+static int getCapFromOriTable_U10per(struct ricoh61x_battery_info *info, int voltage, int currentvalue, int resvalue);
+
+static int calc_ocv(struct ricoh61x_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;
+}
+
+static int calc_soc_on_ocv(struct ricoh61x_battery_info *info, int Ocv)
+{
+ int i;
+ int capacity=0;
+
+ /* capacity is 0.01% unit */
+ if (info->soca->ocv_table[0] >= Ocv) {
+ capacity = 1 * 100;
+ } else if (info->soca->ocv_table[10] <= Ocv) {
+ capacity = 100 * 100;
+ } else {
+ for (i = 1; i < 11; i++) {
+ if (info->soca->ocv_table[i] >= Ocv) {
+ /* unit is 0.01% */
+ capacity = Calc_Linear_Interpolation(
+ (i-1)*10 * 100, info->soca->ocv_table[i-1], i*10 * 100,
+ info->soca->ocv_table[i], Ocv);
+ if(capacity < 100){
+ capacity = 100;
+ }
+ break;
+ }
+ }
+ }
+
+ printk(KERN_INFO "PMU: %s capacity(%d)\n",
+ __func__, capacity);
+
+ return capacity;
+}
+
+static int set_Rlow(struct ricoh61x_battery_info *info)
+{
+ int err;
+ int Rbat_low_max;
+ uint8_t val;
+ int Vocv;
+ int temp;
+
+ if (info->soca->Rbat == 0)
+ info->soca->Rbat = get_OCV_init_Data(info, 12, USING) * 1000 / 512
+ * 5000 / 4095;
+
+ Vocv = calc_ocv(info);
+ Rbat_low_max = info->soca->Rbat * 1.5;
+
+ if (Vocv < get_OCV_voltage(info,3, USING))
+ {
+ info->soca->R_low = Calc_Linear_Interpolation(info->soca->Rbat,get_OCV_voltage(info,3,USING),
+ Rbat_low_max, get_OCV_voltage(info,0,USING), Vocv);
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU: Modify RBAT from %d to %d ", info->soca->Rbat, info->soca->R_low);
+#endif
+ temp = info->soca->R_low *4095/5000*512/1000;
+
+ val = temp >> 8;
+ err = ricoh61x_write_bank1(info->dev->parent, 0xD4, val);
+ if (err < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return err;
+ }
+
+ val = info->soca->R_low & 0xff;
+ err = ricoh61x_write_bank1(info->dev->parent, 0xD5, val);
+ if (err < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return err;
+ }
+ }
+ else info->soca->R_low = 0;
+
+
+ return err;
+}
+
+static int Set_back_ocv_table(struct ricoh61x_battery_info *info)
+{
+ int err;
+ uint8_t val;
+ int temp;
+ int i;
+ uint8_t debug_disp[22];
+
+ /* Modify back ocv table */
+
+ if (0 != info->soca->ocv_table_low[0])
+ {
+ for (i = 0 ; i < 11; i++){
+ battery_init_para[info->num][i*2 + 1] = info->soca->ocv_table_low[i];
+ battery_init_para[info->num][i*2] = info->soca->ocv_table_low[i] >> 8;
+ }
+ err = ricoh61x_clr_bits(info->dev->parent, FG_CTRL_REG, 0x01);
+
+ err = ricoh61x_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 22, battery_init_para[info->num]);
+
+ err = ricoh61x_set_bits(info->dev->parent, FG_CTRL_REG, 0x01);
+
+ /* debug comment start*/
+ err = ricoh61x_bulk_reads_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 22, debug_disp);
+ for (i = 0; i < 11; i++){
+ printk("PMU : %s : after OCV table %d 0x%x\n",__func__, i * 10, (debug_disp[i*2] << 8 | debug_disp[i*2+1]));
+ }
+ /* end */
+ /* clear table*/
+ for(i = 0; i < 11; i++)
+ {
+ info->soca->ocv_table_low[i] = 0;
+ }
+ }
+
+ /* Modify back Rbat */
+ if (0!=info->soca->R_low)
+ {
+ printk("PMU: Modify back RBAT from %d to %d ", info->soca->R_low,info->soca->Rbat);
+ temp = info->soca->Rbat*4095/5000*512/1000;
+
+ val = temp >> 8;
+ err = ricoh61x_write_bank1(info->dev->parent, 0xD4, val);
+ if (err < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return err;
+ }
+
+ val = info->soca->R_low & 0xff;
+ err = ricoh61x_write_bank1(info->dev->parent, 0xD5, val);
+ if (err < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return err;
+ }
+
+ info->soca->R_low = 0;
+ }
+ return 0;
+}
+
+/**
+**/
+static int ricoh61x_Check_OCV_Offset(struct ricoh61x_battery_info *info)
+{
+ int ocv_table[11]; // HEX value
+ int i;
+ int temp;
+ int ret;
+ uint8_t debug_disp[22];
+ uint8_t val = 0;
+
+ printk("PMU : %s : calc ocv %d get OCV %d\n",__func__,calc_ocv(info),get_OCV_voltage(info, RICOH61x_OCV_OFFSET_BOUND,USING));
+
+ /* check adp/usb status */
+ ret = ricoh61x_read(info->dev->parent, CHGSTATE_REG, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return 0;
+ }
+
+ val = (val & 0xC0) >> 6;
+
+ if (val != 0){ /* connect adp or usb */
+ if (calc_ocv(info) < get_OCV_voltage(info, RICOH61x_OCV_OFFSET_BOUND,USING) )
+ {
+ if(0 == info->soca->ocv_table_low[0]){
+ for (i = 0 ; i < 11; i++){
+ ocv_table[i] = (battery_init_para[info->num][i*2]<<8) | (battery_init_para[info->num][i*2+1]);
+ printk("PMU : %s : OCV table %d 0x%x\n",__func__,i * 10, ocv_table[i]);
+ info->soca->ocv_table_low[i] = ocv_table[i];
+ }
+
+ for (i = 0 ; i < 11; i++){
+ temp = ocv_table[i] * (100 + RICOH61x_OCV_OFFSET_RATIO) / 100;
+
+ battery_init_para[info->num][i*2 + 1] = temp;
+ battery_init_para[info->num][i*2] = temp >> 8;
+ }
+ ret = ricoh61x_clr_bits(info->dev->parent, FG_CTRL_REG, 0x01);
+
+ ret = ricoh61x_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 22, battery_init_para[info->num]);
+
+ ret = ricoh61x_set_bits(info->dev->parent, FG_CTRL_REG, 0x01);
+
+ /* debug comment start*/
+ ret = ricoh61x_bulk_reads_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 22, debug_disp);
+ for (i = 0; i < 11; i++){
+ printk("PMU : %s : after OCV table %d 0x%x\n",__func__, i * 10, (debug_disp[i*2] << 8 | debug_disp[i*2+1]));
+ }
+ /* end */
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int reset_FG_process(struct ricoh61x_battery_info *info)
+{
+ int err;
+
+ //err = set_Rlow(info);
+ //err = ricoh61x_Check_OCV_Offset(info);
+ err = ricoh61x_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ info->soca->ready_fg = 0;
+ info->soca->rsoc_ready_flag = 1;
+
+ return err;
+}
+
+
+static int check_charge_status_2(struct ricoh61x_battery_info *info, int displayed_soc_temp)
+{
+ if (displayed_soc_temp < 0)
+ displayed_soc_temp = 0;
+
+ get_power_supply_status(info);
+ info->soca->soc = calc_capacity(info) * 100;
+
+ if (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status) {
+ if ((info->first_pwon == 1)
+ && (RICOH61x_SOCA_START == info->soca->status)) {
+ g_full_flag = 1;
+ info->soca->soc_full = info->soca->soc;
+ info->soca->displayed_soc = 100*100;
+ info->soca->full_reset_count = 0;
+ } else {
+ if (calc_ocv(info) > get_OCV_voltage(info, 9,USING)){
+ g_full_flag = 1;
+ info->soca->soc_full = info->soca->soc;
+ info->soca->displayed_soc = 100*100;
+ info->soca->full_reset_count = 0;
+ } else {
+ g_full_flag = 0;
+ info->soca->displayed_soc = displayed_soc_temp;
+ printk(KERN_INFO "PMU: %s Charge Complete but OCV is low\n", __func__);
+ }
+
+ }
+ }
+ if (info->soca->Ibat_ave >= 0) {
+ if (g_full_flag == 1) {
+ info->soca->displayed_soc = 100*100;
+ } else {
+ info->soca->displayed_soc = min(9949, displayed_soc_temp);
+ }
+ }
+ if (info->soca->Ibat_ave < 0) {
+ if (g_full_flag == 1) {
+ if (calc_ocv(info) < get_OCV_voltage(info, 9, USING) + (get_OCV_voltage(info, 10, USING) - get_OCV_voltage(info, 9, USING))*7/10) {
+ g_full_flag = 0;
+ //info->soca->displayed_soc = 100*100;
+ info->soca->displayed_soc = displayed_soc_temp;
+ printk(KERN_INFO "PMU: %s g_full_flag=1 but OCV is low\n", __func__);
+ } else {
+ info->soca->displayed_soc = 100*100;
+ }
+ } else {
+ info->soca->displayed_soc = min(9949, displayed_soc_temp);
+ g_full_flag = 0;
+ }
+ }
+ if (RICOH61x_SOCA_START == info->soca->status) {
+ if ((g_full_flag == 1) && (calc_ocv(info) > get_OCV_voltage(info, 9,USING))){
+ info->soca->soc_full = info->soca->soc;
+ info->soca->displayed_soc = 100*100;
+ info->soca->full_reset_count = 0;
+ printk(KERN_INFO "PMU:%s Charge Complete in PowerOff\n", __func__);
+ } else if ((info->first_pwon == 0)
+ && !g_fg_on_mode) {
+ printk(KERN_INFO "PMU:%s 2nd P-On init_pswr(%d), cc(%d)\n",
+ __func__, info->soca->init_pswr, info->soca->cc_delta);
+ if ((info->soca->init_pswr == 100)
+ && (info->soca->cc_delta > -100)) {
+ printk(KERN_INFO "PMU:%s Set 100%%\n", __func__);
+ g_full_flag = 1;
+ info->soca->soc_full = info->soca->soc;
+ info->soca->displayed_soc = 100*100;
+ info->soca->full_reset_count = 0;
+ }
+ }
+ } else {
+ printk(KERN_INFO "PMU:%s Resume Sus_soc(%d), cc(%d)\n",
+ __func__, info->soca->suspend_soc, info->soca->cc_delta);
+ if ((info->soca->suspend_soc == 10000)
+ && (info->soca->cc_delta > -100)) {
+ printk(KERN_INFO "PMU:%s Set 100%%\n", __func__);
+ info->soca->displayed_soc = 100*100;
+ }
+ }
+
+ return info->soca->displayed_soc;
+}
+
+/**
+* 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%
+* @cc_cap_mas : capacity in a period, unit 1mAs
+* @is_charging: Flag of charging current direction
+* TRUE : charging (plus)
+* FALSE: discharging (minus)
+* @cc_rst: reset CC_SUM or not
+* 0 : not reset
+* 1 : reset
+* 2 : half reset (Leave under 1% of FACAP)
+**/
+static int calc_capacity_in_period(struct ricoh61x_battery_info *info,
+ int *cc_cap, long *cc_cap_mas, bool *is_charging, int cc_rst)
+{
+ 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;
+ int cc_stop_flag;
+ uint8_t status;
+ uint8_t charge_state;
+ int Ocv;
+ uint32_t cc_cap_temp;
+ uint32_t cc_cap_min;
+ int cc_cap_res;
+ int fa_cap_int;
+ long cc_sum_int;
+ long cc_sum_dec;
+
+ *is_charging = true; /* currrent state initialize -> charging */
+
+ if (info->entry_factory_mode)
+ return 0;
+
+ /* Read FA_CAP */
+ err = ricoh61x_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;
+
+
+ /* get power supply status */
+ err = ricoh61x_read(info->dev->parent, CHGSTATE_REG, &status);
+ if (err < 0)
+ goto out;
+ charge_state = (status & 0x1F);
+ Ocv = calc_ocv(info);
+ if (charge_state == CHG_STATE_CHG_COMPLETE) {
+ /* Check CHG status is complete or not */
+ cc_stop_flag = 0;
+// } else if (calc_capacity(info) == 100) {
+// /* Check HW soc is 100 or not */
+// cc_stop_flag = 0;
+ } else if (Ocv < get_OCV_voltage(info, 9, USING)) {
+ /* Check VBAT is high level or not */
+ cc_stop_flag = 0;
+ } else {
+ cc_stop_flag = 1;
+ }
+
+ if (cc_stop_flag == 1)
+ {
+ /* Disable Charging/Completion Interrupt */
+ err = ricoh61x_set_bits(info->dev->parent,
+ RICOH61x_INT_MSK_CHGSTS1, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* disable charging */
+ err = ricoh61x_clr_bits(info->dev->parent, RICOH61x_CHG_CTL1, 0x03);
+ if (err < 0)
+ goto out;
+ }
+
+ /* Read CC_SUM */
+ err = ricoh61x_bulk_reads(info->dev->parent,
+ CC_SUMREG3_REG, 4, cc_sum_reg);
+ if (err < 0)
+ goto out;
+
+ /* cc_sum = *(uint32_t*)cc_sum_reg; */
+ cc_sum = cc_sum_reg[0] << 24 | cc_sum_reg[1] << 16 |
+ cc_sum_reg[2] << 8 | cc_sum_reg[3];
+
+ /* calculation two's complement of CC_SUM */
+ if (cc_sum & 0x80000000) {
+ cc_sum = (cc_sum^0xffffffff)+0x01;
+ *is_charging = false; /* discharge */
+ }
+
+ if (cc_rst == 1) {
+ /* CC_pause enter */
+ err = ricoh61x_write(info->dev->parent, CC_CTRL_REG, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* CC_SUM <- 0 */
+ err = ricoh61x_bulk_writes(info->dev->parent,
+ CC_SUMREG3_REG, 4, cc_clr);
+ if (err < 0)
+ goto out;
+ } else if (cc_rst == 2) {
+ /* Check 1%[mAs] of FA_CAP (FA_CAP * 3600 /100) */
+ fa_cap_int = fa_cap * 36;
+ cc_sum_int = cc_sum / fa_cap_int;
+ cc_sum_dec = cc_sum % fa_cap_int;
+
+ if (*is_charging == false) {
+ cc_sum_dec = (cc_sum_dec^0xffffffff) + 1;
+ }
+ printk(KERN_INFO "PMU %s 1%%FACAP(%d)[mAs], cc_sum(%d)[mAs], cc_sum_dec(%d)\n",
+ __func__, fa_cap_int, cc_sum, cc_sum_dec);
+
+ if (cc_sum_int != 0) {
+ cc_clr[0] = (uint8_t)(cc_sum_dec >> 24) & 0xff;
+ cc_clr[1] = (uint8_t)(cc_sum_dec >> 16) & 0xff;
+ cc_clr[2] = (uint8_t)(cc_sum_dec >> 8) & 0xff;
+ cc_clr[3] = (uint8_t)cc_sum_dec & 0xff;
+
+ /* CC_pause enter */
+ err = ricoh61x_write(info->dev->parent, CC_CTRL_REG, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* CC_SUM <- 0 */
+ err = ricoh61x_bulk_writes(info->dev->parent,
+ CC_SUMREG3_REG, 4, cc_clr);
+ if (err < 0)
+ goto out;
+ printk(KERN_INFO "PMU %s Half-Clear CC, cc_sum is over 1%%\n",
+ __func__);
+ }
+ }
+
+ /* CC_pause exist */
+ err = ricoh61x_write(info->dev->parent, CC_CTRL_REG, 0);
+ if (err < 0)
+ goto out;
+ if (cc_stop_flag == 1)
+ {
+
+ /* Enable charging */
+ err = ricoh61x_set_bits(info->dev->parent, RICOH61x_CHG_CTL1, 0x03);
+ if (err < 0)
+ goto out;
+
+ udelay(1000);
+
+ /* Clear Charging Interrupt status */
+ err = ricoh61x_clr_bits(info->dev->parent,
+ RICOH61x_INT_IR_CHGSTS1, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* ricoh61x_read(info->dev->parent, RICOH61x_INT_IR_CHGSTS1, &val);
+// printk("INT_IR_CHGSTS1 = 0x%x\n",val); */
+
+ /* Enable Charging Interrupt */
+ err = ricoh61x_clr_bits(info->dev->parent,
+ RICOH61x_INT_MSK_CHGSTS1, 0x01);
+ if (err < 0)
+ goto out;
+ }
+
+ /* (CC_SUM x 10000)/3600/FA_CAP */
+
+ if(fa_cap == 0)
+ goto out;
+ else
+ *cc_cap = cc_sum*25/9/fa_cap; /* unit is 0.01% */
+
+ *cc_cap_mas = cc_sum;
+
+ //printk("PMU: cc_sum = %d: cc_cap= %d: cc_cap_mas = %d\n", cc_sum, *cc_cap, *cc_cap_mas);
+
+ if (cc_rst == 1) {
+ cc_cap_min = fa_cap*3600/100/100/100; /* Unit is 0.0001% */
+
+ if(cc_cap_min == 0)
+ goto out;
+ else
+ cc_cap_temp = cc_sum / cc_cap_min;
+
+ cc_cap_res = cc_cap_temp % 100;
+
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU: cc_sum = %d: cc_cap_res= %d: cc_cap_mas = %d\n", cc_sum, cc_cap_res, cc_cap_mas);
+#endif
+
+ if(*is_charging) {
+ info->soca->cc_cap_offset += cc_cap_res;
+ if (info->soca->cc_cap_offset >= 100) {
+ *cc_cap += 1;
+ info->soca->cc_cap_offset %= 100;
+ }
+ } else {
+ info->soca->cc_cap_offset -= cc_cap_res;
+ if (info->soca->cc_cap_offset <= -100) {
+ *cc_cap += 1;
+ info->soca->cc_cap_offset %= 100;
+ }
+ }
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU: cc_cap_offset= %d: \n", info->soca->cc_cap_offset);
+#endif
+ } else {
+ info->soca->cc_cap_offset = 0;
+ }
+
+ //////////////////////////////////////////////////////////////////
+ return 0;
+out:
+ /* CC_pause exist */
+ err = ricoh61x_write(info->dev->parent, CC_CTRL_REG, 0);
+
+ dev_err(info->dev, "Error !!-----\n");
+ return err;
+}
+
+/**
+* Initial setting of Low voltage.
+**/
+static void initSettingOfLowVoltage(struct ricoh61x_battery_info *info)
+{
+ int err;
+ int cc_cap;
+ long cc_cap_mas;
+ bool is_charging = true;
+
+
+ if(info->soca->rsoc_ready_flag ==1) {
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 1);
+ info->soca->last_cc_delta_cap = 0;
+ } else {
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 0);
+ info->soca->last_cc_delta_cap = (is_charging == true) ? cc_cap : -cc_cap;
+ }
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ return;
+}
+
+/**
+* Low voltage main flow.
+**/
+static void mainFlowOfLowVoltage(struct ricoh61x_battery_info *info)
+{
+ int ret = 0;
+ int cc_cap = 0;
+ long cc_cap_mas = 0;
+ bool is_charging = true;
+ int cc_delta_cap;
+ int cc_delta_cap_temp;
+ int cc_delta_cap_mas_temp;
+ int cc_delta_cap_now;
+ int cc_delta_cap_debug; //for debug value
+ int capacity_now; //Unit is 0.01 %
+ int capacity_zero; //Unit is 0.01 %
+ int capacity_remain; //Unit is 0.01 %
+ int low_rate; //Unit is 0.01 times
+ int target_equal_soc; //unit is 0.01 %
+ int temp_cc_delta_cap; //unit is 0.01 %
+ int fa_cap; //unit is mAh
+
+ if(info->soca->rsoc_ready_flag ==1) {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 1);
+ } else {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 0);
+ }
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ if(is_charging == true) {
+ cc_delta_cap_now = cc_cap;
+ //cc_cap_mas;
+ } else {
+ cc_delta_cap_now = -cc_cap;
+ cc_cap_mas = -cc_cap_mas;
+ }
+
+ fa_cap = (battery_init_para[info->num][22]<<8)
+ | (battery_init_para[info->num][23]);
+
+ if(fa_cap != 0) {
+ //( cc(mas) * 10000 ) / 3600 / fa_cap
+ temp_cc_delta_cap = info->soca->temp_cc_delta_cap_mas * 25 / 9 / fa_cap;
+ } else {
+ temp_cc_delta_cap = 0;
+ }
+
+ cc_delta_cap = (cc_delta_cap_now - info->soca->last_cc_delta_cap) + temp_cc_delta_cap;
+
+// info->soca->temp_cc_delta_cap_mas = info->soca->temp_cc_delta_cap_mas - ( (fa_cap * 3600) * (temp_cc_delta_cap / 10000)) ;
+ info->soca->temp_cc_delta_cap_mas = info->soca->temp_cc_delta_cap_mas - ( ((fa_cap * 9) / 25) * temp_cc_delta_cap);
+
+ printk(KERN_DEBUG "PMU: %s : Noxx : cc_delta_cap is %d, cc_delta_cap_now is %d, last_cc_delta_cap is %d\n"
+ , __func__, cc_delta_cap, cc_delta_cap_now, info->soca->last_cc_delta_cap);
+ printk(KERN_DEBUG "PMU: %s : Noxx : temp_cc_delta_cap is %d, after temp_cc_delta_cap_mas is %ld, cc_cap_mas %ld\n"
+ , __func__, temp_cc_delta_cap ,info->soca->temp_cc_delta_cap_mas, cc_cap_mas);
+
+ if(info->soca->rsoc_ready_flag ==1) {
+ info->soca->last_cc_delta_cap = 0;
+ info->soca->last_cc_delta_cap_mas = 0;
+ } else {
+ info->soca->last_cc_delta_cap = cc_delta_cap_now;
+ info->soca->last_cc_delta_cap_mas = cc_cap_mas;
+ }
+
+ cc_delta_cap_debug = cc_delta_cap;
+
+ // check charging or not, if charging -> move to Disp state
+ if ((cc_delta_cap > 0) ||
+ (info->soca->Ibat_ave >= 0)){//chekc discharging or not
+ info->soca->soc = calc_capacity(info) * 100;
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->last_soc = info->soca->soc;
+ info->soca->soc_delta = 0;
+ info->soca->hurry_up_flg = 0;
+ info->soca->temp_cc_delta_cap_mas = 0;
+ return;
+ }
+
+ //check Vbat and POff_vbat
+ if(info->soca->Vbat_ave <= (info->fg_poff_vbat * 1000)) {
+ info->soca->displayed_soc = info->soca->displayed_soc - 100;
+ info->soca->displayed_soc = max(0, info->soca->displayed_soc);
+ info->soca->hurry_up_flg = 1;
+ return;
+ }
+
+ //calc current recap value
+ capacity_now = getCapFromOriTable(info,info->soca->Vbat_ave,info->soca->Ibat_ave,info->soca->Rbat);
+
+ //calc recap value when soc is 0%
+ if(info->fg_poff_vbat != 0){
+ //enable poff vbat
+ capacity_zero = getCapFromOriTable(info,(info->fg_poff_vbat * 1000),info->soca->Ibat_ave,info->soca->Rbat);
+ } else if(info->fg_target_vsys != 0){
+ //enable target vsys
+ capacity_zero = getCapFromOriTable(info,(info->fg_target_vsys * 1000),info->soca->Ibat_ave,info->soca->Rsys);
+ } else {
+ //disable poff vbat and target vsys
+ capacity_zero = 0;
+ }
+
+ capacity_remain = (capacity_now - capacity_zero) + 50;
+
+ if (capacity_remain <= 50){
+ printk(KERN_INFO "PMU: %s : No6 :Hurry up!!! \n", __func__);
+ info->soca->displayed_soc = info->soca->displayed_soc - 100;
+ info->soca->displayed_soc = max(0, info->soca->displayed_soc);
+ info->soca->hurry_up_flg = 1;
+ return;
+ }
+ else {
+ info->soca->hurry_up_flg = 0;
+
+ if (info->soca->displayed_soc < 1000) { //low DSOC case
+ if(capacity_remain > info->soca->displayed_soc){
+ target_equal_soc = info->soca->displayed_soc * 95 / 100;
+ } else {
+ target_equal_soc = 50;
+ }
+ } else {// normal case
+ if(capacity_remain > info->soca->displayed_soc){
+ target_equal_soc = info->soca->displayed_soc - 1000;
+ } else {
+ target_equal_soc = capacity_remain - 1000;
+ }
+ }
+
+ target_equal_soc = max(50, target_equal_soc);
+
+ low_rate = (info->soca->displayed_soc - target_equal_soc) * 100 / (capacity_remain - target_equal_soc);
+
+ low_rate = max(1, low_rate);
+ low_rate = min(300, low_rate);
+
+ cc_delta_cap_temp = cc_delta_cap * 100 * low_rate / 100; //unit is 0.0001%
+
+ if(cc_delta_cap_temp < 0){
+ //Unit 0.0001 -> 0.01
+ cc_delta_cap = cc_delta_cap_temp / 100;
+
+ cc_delta_cap_temp = cc_delta_cap_temp - cc_delta_cap * 100;
+ //transform 0.0001% -> mAs
+ //mAs = 0.0001 % * (fa_cap(mAh)*60*60)
+ //mAs = cc_delta_cap_temp * (fa_cap * 60 * 60) / (100 * 100 * 100)
+ cc_delta_cap_mas_temp = cc_delta_cap_temp * fa_cap * 9 / 2500;
+ info->soca->temp_cc_delta_cap_mas += cc_delta_cap_mas_temp;
+ }else{
+ cc_delta_cap = 0;
+ }
+
+ info->soca->displayed_soc = info->soca->displayed_soc + cc_delta_cap;
+ info->soca->displayed_soc = max(100, info->soca->displayed_soc); //Set Under limit DSOC is 1%
+ printk(KERN_DEBUG "PMU: %s : No9 :Cap is %d , low_rate is %d, dsoc is %d, capnow is %d, capzero is %d, delta cc is %d, delta cc ori is %d\n"
+ , __func__, capacity_remain, low_rate, info->soca->displayed_soc, capacity_now, capacity_zero, cc_delta_cap, cc_delta_cap_debug);
+ printk(KERN_DEBUG "PMU: %s : No10 :temp_mas is %d, offset_mas is %d, value is %d, final value is %d\n"
+ , __func__, info->soca->temp_cc_delta_cap_mas, cc_delta_cap_mas_temp,(cc_delta_cap_temp + cc_delta_cap * 100), cc_delta_cap);
+ }
+ return;
+}
+
+/**
+* get capacity from Original OCV Table. this value is calculted by ocv
+* info : battery info
+* voltage : unit is 1mV
+* current : unit is 1mA
+* resvalue: unit is 1mohm
+*
+* return value : capcaity, unit is 0.01%
+*/
+static int getCapFromOriTable(struct ricoh61x_battery_info *info, int voltage, int currentvalue, int resvalue)
+{
+ int ocv = 0;
+ int i =0;
+ int capacity=0;
+
+ int ocv_table[11];
+
+ ocv = voltage - (currentvalue * resvalue);
+
+ //get ocv table from header file
+ for(i = 0; i < 11; i++){
+ ocv_table[i] = get_OCV_voltage(info, i, ORIGINAL);
+ }
+
+ /* capacity is 0.01% unit */
+ if (ocv_table[10] <= ocv) {
+ capacity = 100 * 100;
+ } else {
+ for (i = 1; i < 11; i++) {
+ if (ocv_table[i] >= ocv) {
+ if(i == 1){//Under 10 %
+ capacity = getCapFromOriTable_U10per(info, voltage, currentvalue, resvalue);
+ }else{
+ /* unit is 0.01% */
+ capacity = Calc_Linear_Interpolation(
+ (i-1)*10 * 100, ocv_table[i-1], i*10 * 100,
+ ocv_table[i], ocv);
+ if(capacity < 100){
+ capacity = 100;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return capacity;
+}
+
+/**
+* get capacity from special OCV Table(10%-0%). this value is calculted by ocv
+* info : battery info
+* voltage : unit is 1mV
+* current : unit is 1mA
+* resvalue: unit is 1mohm
+*
+* return value : capcaity, unit is 0.01%
+*/
+static int getCapFromOriTable_U10per(struct ricoh61x_battery_info *info, int voltage, int currentvalue, int resvalue)
+{
+ int ocv = 0;
+ int i =0;
+ int capacity=0;
+
+ int ocv_table[11] = { 3468207,
+ 3554926,
+ 3605932,
+ 3627745,
+ 3639093,
+ 3646930,
+ 3655757,
+ 3665738,
+ 3672731,
+ 3680469,
+ 3687400};
+
+ ocv = voltage - (currentvalue * resvalue);
+
+ /* capacity is 0.01% unit */
+ if (ocv_table[0] >= ocv) {
+ capacity = 0;
+ } else if (ocv_table[10] <= ocv) {
+ capacity = 10 * 100;
+ } else {
+ for (i = 1; i < 11; i++) {
+ if (ocv_table[i] >= ocv) {
+ /* unit is 0.01% */
+ capacity = Calc_Linear_Interpolation(
+ (i-1) * 100, ocv_table[i-1], i * 100,
+ ocv_table[i], ocv);
+ if(capacity < 0){
+ capacity = 0;
+ }
+ break;
+ }
+ }
+ }
+ return capacity;
+
+}
+
+/**
+* ReWrite extra CC Value to CC_SUM(register)
+* info : battery info
+* extraValue : Under 1% value. unit is 0.01%
+*
+* return value : delta soc, unit is "minus" 0.01%
+*/
+
+static void write_extra_value_to_ccsum(struct ricoh61x_battery_info *info, int extraValue)
+{
+ int err;
+ uint8_t cc_clr[4] = {0, 0, 0, 0}; //temporary box
+ uint8_t fa_cap_reg[2]; //reg value
+ int fa_cap; //Unit is mAh
+ int cc_sum_dec; //unit is mAs
+ bool is_charging = 0;
+
+ //check dicharging or not
+ if(extraValue < 0){
+ extraValue = extraValue * -1;
+ is_charging = false;
+ } else {
+ is_charging = true;
+ }
+
+ /* Read FA_CAP */
+ err = ricoh61x_bulk_reads(info->dev->parent,
+ FA_CAP_H_REG, 2, fa_cap_reg);
+ if (err < 0)
+ dev_err(info->dev, "Read fa_cap Error !!-----\n");
+
+ /* fa_cap = *(uint16_t*)fa_cap_reg & 0x7fff; */
+ fa_cap = (fa_cap_reg[0] << 8 | fa_cap_reg[1]) & 0x7fff;
+
+ //convertion extraValue(0.01%) -> mAs
+ //cc_sum_dec = (extraValue * fa_cap * 3600) / (100 * 100)
+ cc_sum_dec = (extraValue * fa_cap * 9) / 25;
+
+ // Add 0.005%
+ if (extraValue < 100) {
+ cc_sum_dec += (1 * fa_cap * 9) / 25;
+ }
+
+ if (is_charging == false) {
+ cc_sum_dec = (cc_sum_dec^0xffffffff) + 1;
+ }
+
+ cc_clr[0] = (uint8_t)(cc_sum_dec >> 24) & 0xff;
+ cc_clr[1] = (uint8_t)(cc_sum_dec >> 16) & 0xff;
+ cc_clr[2] = (uint8_t)(cc_sum_dec >> 8) & 0xff;
+ cc_clr[3] = (uint8_t)cc_sum_dec & 0xff;
+
+ /* CC_pause enter */
+ err = ricoh61x_write(info->dev->parent, CC_CTRL_REG, 0x01);
+ if (err < 0)
+ dev_err(info->dev, "Write cc_CTRL Error !!-----\n");
+
+ /* CC_SUM <- 0 */
+ err = ricoh61x_bulk_writes(info->dev->parent,
+ CC_SUMREG3_REG, 4, cc_clr);
+ if (err < 0)
+ dev_err(info->dev, "Write cc_Sum Error !!-----\n");
+
+ /* CC_pause exit */
+ err = ricoh61x_write(info->dev->parent, CC_CTRL_REG, 0);
+ if (err < 0)
+ dev_err(info->dev, "Write cc_CTRL Error !!-----\n");
+
+ return;
+}
+
+
+#ifdef ENABLE_OCV_TABLE_CALIB
+/**
+* Calibration OCV Table
+* - Update the value of VBAT on 100% in OCV table
+* if battery is Full charged.
+* - int vbat_ocv <- unit is uV
+**/
+static int calib_ocvTable(struct ricoh61x_battery_info *info, int vbat_ocv)
+{
+ int ret;
+ int cutoff_ocv;
+ int i;
+ int ocv100_new;
+ int start_per = 0;
+ int end_per = 0;
+
+ if (info->soca->Ibat_ave > RICOH61x_REL1_SEL_VALUE) {
+ printk("PMU: %s IBAT > 64mA -- Not Calibration --\n", __func__);
+ return 0;
+ }
+
+ if (vbat_ocv < info->soca->OCV100_max) {
+ if (vbat_ocv < info->soca->OCV100_min)
+ ocv100_new = info->soca->OCV100_min;
+ else
+ ocv100_new = vbat_ocv;
+ } else {
+ ocv100_new = info->soca->OCV100_max;
+ }
+ printk("PMU : %s :max %d min %d current %d\n",__func__,info->soca->OCV100_max,info->soca->OCV100_min,vbat_ocv);
+ printk("PMU : %s : New OCV 100 = 0x%x\n",__func__,ocv100_new);
+
+ /* FG_En Off */
+ ret = ricoh61x_clr_bits(info->dev->parent, FG_CTRL_REG, 0x01);
+ if (ret < 0) {
+ dev_err(info->dev,"Error in FG_En OFF\n");
+ goto err;
+ }
+
+
+ //cutoff_ocv = (battery_init_para[info->num][0]<<8) | (battery_init_para[info->num][1]);
+ cutoff_ocv = get_OCV_voltage(info, 0, USING);
+
+ info->soca->ocv_table_def[10] = info->soca->OCV100_max;
+
+ ricoh61x_scaling_OCV_table(info, cutoff_ocv/1000, ocv100_new/1000, &start_per, &end_per);
+
+ ret = ricoh61x_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 22, battery_init_para[info->num]);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ for (i = 0; i <= 10; i = i+1) {
+ info->soca->ocv_table[i] = get_OCV_voltage(info, i, USING);
+ printk("PMU: %s : * %d0%% voltage = %d uV\n",
+ __func__, i, info->soca->ocv_table[i]);
+ }
+
+ /* FG_En on & Reset*/
+ ret = reset_FG_process(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in FG_En On & Reset %d\n", ret);
+ goto err;
+ }
+
+ printk("PMU: %s Exit \n", __func__);
+ return 0;
+err:
+ return ret;
+
+}
+
+#endif
+
+/**
+* get SOC value during period of Suspend/Hibernate with voltage method
+* info : battery info
+*
+* return value : soc, unit is 0.01%
+*/
+
+static int calc_soc_by_voltageMethod(struct ricoh61x_battery_info *info)
+{
+ int soc;
+ int ret;
+
+ ret = measure_vbatt_FG(info, &info->soca->Vbat_ave);
+
+ if(info->soca->Vbat_ave > 4100000) {
+ soc = 10000;
+ } else if(info->soca->Vbat_ave < 3500000) {
+ soc = 0;
+ } else {
+ soc = 10000 - ((4100000 - info->soca->Vbat_ave) / 60);
+ }
+
+ get_power_supply_status(info);
+ if (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status) {
+ soc = 10000;
+ } else {
+ soc = min(soc, 9900);
+ }
+
+ // Cutoff under 1% on Voltage Method
+ soc = (soc / 100) * 100;
+
+ printk("PMU : %s : VBAT is %d [uV], soc is %d [0.01%%] ----------\n"
+ ,__func__, info->soca->Vbat_ave, soc);
+
+ // soc range is 0~10000
+ return soc;
+}
+
+/**
+* update RSOC and related parameters after using voltage method
+* info : battery info
+* soc_voltage : soc by using voltage method
+*
+*/
+
+static void update_rsoc_on_voltageMethod(struct ricoh61x_battery_info *info, int soc_voltage)
+{
+ info->soca->init_pswr = soc_voltage / 100;
+ write_extra_value_to_ccsum(info, (soc_voltage % 100));
+ info->soca->status = RICOH61x_SOCA_STABLE;
+ info->soca->last_soc = soc_voltage;
+ info->soca->rsoc_ready_flag = 0;
+
+ printk(KERN_INFO "PMU: %s : Voltage Method. state(%d), dsoc(%d), rsoc(%d), init_pswr(%d), cc_delta(%d) ----------\n",
+ __func__, info->soca->status, soc_voltage, soc_voltage, info->soca->init_pswr, soc_voltage%100);
+
+ return;
+}
+
+/**
+* update RSOC and related parameters after using current method
+* Only resume function can call this one.
+* info : battery info
+* soc_current : soc by using current method
+*
+*/
+
+static void update_rsoc_on_currentMethod(struct ricoh61x_battery_info *info, int soc_current)
+{
+ int resume_rsoc;
+
+ if (RICOH61x_SOCA_START == info->soca->status
+ || RICOH61x_SOCA_UNSTABLE == info->soca->status
+ || RICOH61x_SOCA_STABLE == info->soca->status) {
+ resume_rsoc = soc_current;
+ } else {
+ resume_rsoc = info->soca->suspend_rsoc + info->soca->cc_delta;
+ }
+ resume_rsoc = max(0, min(10000, resume_rsoc)); // Apply upper&lower limit
+ info->soca->init_pswr = resume_rsoc / 100;
+ write_extra_value_to_ccsum(info, (resume_rsoc % 100));
+ info->soca->rsoc_ready_flag = 0;
+ printk(KERN_INFO "PMU: %s : Current Method. state(%d), dsoc(%d), rsoc(%d), init_pswr(%d), cc_delta(%d) ----------\n",
+ __func__, info->soca->status, soc_current, resume_rsoc, info->soca->init_pswr, resume_rsoc%100);
+
+ return;
+}
+
+
+static void ricoh61x_displayed_work(struct work_struct *work)
+{
+ int err;
+ uint8_t val;
+ uint8_t val_pswr;
+ uint8_t val2;
+ int soc_round;
+ int last_soc_round;
+ int last_disp_round;
+ int displayed_soc_temp;
+ int disp_dec;
+ int cc_cap = 0;
+ long cc_cap_mas = 0;
+ bool is_charging = true;
+ int re_cap,fa_cap,use_cap;
+ bool is_jeita_updated;
+ uint8_t reg_val;
+ int delay_flag = 0;
+ int Vbat = 0;
+ int Ibat = 0;
+ int Vsys = 0;
+ int temp_ocv;
+ int current_soc_full;
+ int fc_delta = 0;
+ int temp_soc;
+ int current_cc_sum;
+ int calculated_ocv;
+ long full_rate = 0;
+ long full_rate_org;
+ long full_rate_max;
+ long full_rate_min;
+ int temp_cc_delta_cap;
+ int ibat_soc = 0;
+ int ibat_soc_base;
+ int dsoc_var;
+ int dsoc_var_org;
+ int cc_delta;
+ int i;
+ int last_dsoc;
+
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, displayed_work.work);
+
+ if (info->entry_factory_mode) {
+ info->soca->status = RICOH61x_SOCA_STABLE;
+ info->soca->displayed_soc = -EINVAL;
+ info->soca->ready_fg = 0;
+ return;
+ }
+
+ if (info->stop_disp) {
+ printk(KERN_INFO "PMU: Finish displayed_work func\n",
+ __func__);
+ return;
+ }
+
+ mutex_lock(&info->lock);
+
+ is_jeita_updated = false;
+
+ if ((RICOH61x_SOCA_START == info->soca->status)
+ || (RICOH61x_SOCA_STABLE == info->soca->status)
+ || (RICOH61x_SOCA_FULL == info->soca->status))
+ {
+ info->soca->ready_fg = 1;
+ }
+ //if (RICOH61x_SOCA_FG_RESET != info->soca->status)
+ // Set_back_ocv_table(info);
+
+ if (bat_alert_req_flg == 1) {
+ // Use Voltage method if difference is large
+ info->soca->displayed_soc = calc_soc_by_voltageMethod(info);
+ update_rsoc_on_voltageMethod(info, info->soca->displayed_soc);
+ bat_alert_req_flg = 0;
+
+ goto end_flow;
+ }
+
+ /* judge Full state or Moni Vsys state */
+ calculated_ocv = calc_ocv(info);
+ if ((RICOH61x_SOCA_DISP == info->soca->status)
+ || (RICOH61x_SOCA_STABLE == info->soca->status)) {
+ /* caluc 95% ocv */
+ temp_ocv = get_OCV_voltage(info, 10, USING) -
+ (get_OCV_voltage(info, 10, USING) - get_OCV_voltage(info, 9, USING))/2;
+
+ if(g_full_flag == 1){ /* for issue 1 solution start*/
+ info->soca->status = RICOH61x_SOCA_FULL;
+ info->soca->last_soc_full = 0;
+ } else if ((POWER_SUPPLY_STATUS_FULL == info->soca->chg_status)
+ && (calculated_ocv > temp_ocv)) {
+ info->soca->status = RICOH61x_SOCA_FULL;
+ g_full_flag = 0;
+ info->soca->last_soc_full = 0;
+ } else if (info->soca->Ibat_ave >= -12) {
+ /* for issue1 solution end */
+ /* check Full state or not*/
+ if ((calculated_ocv > get_OCV_voltage(info, RICOH61x_ENTER_FULL_STATE_OCV, USING))
+ || (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status)
+ || (info->soca->displayed_soc > RICOH61x_ENTER_FULL_STATE_DSOC * 100)) {
+ info->soca->status = RICOH61x_SOCA_FULL;
+ g_full_flag = 0;
+ info->soca->last_soc_full = 0;
+ } else if ((calculated_ocv > get_OCV_voltage(info, 9, USING))
+ && (info->soca->Ibat_ave < 300)) {
+ info->soca->status = RICOH61x_SOCA_FULL;
+ g_full_flag = 0;
+ info->soca->last_soc_full = 0;
+ }
+ } else { /* dis-charging */
+// if (info->soca->displayed_soc/100 < RICOH61x_ENTER_LOW_VOL) {
+ initSettingOfLowVoltage(info);
+ info->soca->status = RICOH61x_SOCA_LOW_VOL;
+// }
+ }
+ }
+
+ if (RICOH61x_SOCA_STABLE == info->soca->status) {
+ info->soca->soc = calc_capacity_2(info);
+ info->soca->soc_delta = info->soca->soc - info->soca->last_soc;
+
+ if (info->soca->soc_delta >= -100 && info->soca->soc_delta <= 100) {
+ info->soca->displayed_soc = info->soca->soc;
+ } else {
+ info->soca->status = RICOH61x_SOCA_DISP;
+ }
+ info->soca->last_soc = info->soca->soc;
+ info->soca->soc_delta = 0;
+ } else if (RICOH61x_SOCA_FULL == info->soca->status) {
+ err = check_jeita_status(info, &is_jeita_updated);
+ if (err < 0) {
+ dev_err(info->dev, "Error in updating JEITA %d\n", err);
+ goto end_flow;
+ }
+ info->soca->soc = calc_capacity(info) * 100;
+ info->soca->last_soc = calc_capacity_2(info); /* for DISP */
+ last_dsoc = info->soca->displayed_soc;
+
+ if (info->soca->Ibat_ave >= -12) { /* charging */
+ if (0 == info->soca->jt_limit) {
+ if (g_full_flag == 1) {
+
+ if (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status) {
+ if(info->soca->full_reset_count < RICOH61x_UPDATE_COUNT_FULL_RESET) {
+ info->soca->full_reset_count++;
+ } else if (info->soca->full_reset_count < (RICOH61x_UPDATE_COUNT_FULL_RESET + 1)) {
+ err = reset_FG_process(info);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ info->soca->full_reset_count++;
+ info->soca->rsoc_ready_flag =1;
+ goto end_flow;
+ } else if(info->soca->full_reset_count < (RICOH61x_UPDATE_COUNT_FULL_RESET + 2)) {
+ info->soca->full_reset_count++;
+ info->soca->fc_cap = 0;
+ info->soca->soc_full = info->soca->soc;
+ }
+ } else {
+ if(info->soca->fc_cap < -1 * 200) {
+ g_full_flag = 0;
+ info->soca->displayed_soc = 99 * 100;
+ }
+ info->soca->full_reset_count = 0;
+ }
+
+
+ if(info->soca->rsoc_ready_flag ==1) {
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 1);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ fc_delta = (is_charging == true) ? cc_cap : -cc_cap;
+
+ info->soca->fc_cap = info->soca->fc_cap + fc_delta;
+ }
+
+ if (g_full_flag == 1){
+ info->soca->displayed_soc = 100*100;
+ }
+ } else {
+ if ((calculated_ocv < get_OCV_voltage(info, (RICOH61x_ENTER_FULL_STATE_OCV - 1), USING))
+ && (info->soca->displayed_soc < (RICOH61x_ENTER_FULL_STATE_DSOC - 10) * 100)) { /* fail safe*/
+ g_full_flag = 0;
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->soc_delta = 0;
+ info->soca->full_reset_count = 0;
+ info->soca->last_soc = info->soca->soc;
+ info->soca->temp_cc_delta_cap = 0;
+ } else if ((POWER_SUPPLY_STATUS_FULL == info->soca->chg_status)
+ && (info->soca->displayed_soc >= 9890)){
+ info->soca->displayed_soc = 100*100;
+ g_full_flag = 1;
+ info->soca->full_reset_count = 0;
+ info->soca->soc_full = info->soca->soc;
+ info->soca->fc_cap = 0;
+ info->soca->last_soc_full = 0;
+#ifdef ENABLE_OCV_TABLE_CALIB
+ err = calib_ocvTable(info,calculated_ocv);
+ if (err < 0)
+ dev_err(info->dev, "Calibration OCV Error !!\n");
+#endif
+ } else {
+ fa_cap = get_check_fuel_gauge_reg(info, FA_CAP_H_REG, FA_CAP_L_REG,
+ 0x7fff);
+
+ if (info->soca->displayed_soc >= 9950) {
+ if((info->soca->soc_full - info->soca->soc) < 200) {
+ goto end_flow;
+ }
+ }
+
+ /* Calculate CC Delta */
+ if(info->soca->rsoc_ready_flag ==1) {
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 1);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+ } else {
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 0);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ cc_delta = (is_charging == true) ? cc_cap : -cc_cap;
+ current_soc_full = info->soca->init_pswr * 100 + cc_delta;
+
+ if (info->soca->last_soc_full == 0) { /* initial setting of last cc sum */
+ info->soca->cc_delta = 0;
+ info->soca->rsoc_limit = 0;
+ printk(KERN_INFO "PMU: %s 1st last_soc_full(%d), cc_delta=0\n",
+ __func__, info->soca->last_soc_full);
+ } else if (info->soca->rsoc_limit == 1) {
+ info->soca->cc_delta = 100 + current_soc_full - info->soca->last_soc_full;
+ } else {
+ info->soca->cc_delta = current_soc_full - info->soca->last_soc_full;
+ }
+ info->soca->last_soc_full = current_soc_full;
+
+ if ((info->soca->init_pswr == 100) && (cc_delta >= 100)) {
+ info->soca->rsoc_limit = 1;
+ } else {
+ info->soca->rsoc_limit = 0;
+ }
+ }
+
+ printk(KERN_INFO "PMU: %s rrf= %d: cc_delta= %d: current_soc= %d: rsoc_limit= %d: cc_delta_temp = %d:\n",
+ __func__, info->soca->rsoc_ready_flag, info->soca->cc_delta, current_soc_full, info->soca->rsoc_limit,info->soca->temp_cc_delta_cap);
+
+ info->soca->temp_cc_delta_cap = min(800, info->soca->temp_cc_delta_cap);
+
+ info->soca->cc_delta += info->soca->temp_cc_delta_cap;
+ info->soca->temp_cc_delta_cap = 0;
+
+
+#ifdef LTS_DEBUG
+ printk(KERN_INFO "PMU: %s rrf= %d: cc_delta= %d: current_soc= %d: rsoc_limit= %d:\n",
+ __func__, info->soca->rsoc_ready_flag, info->soca->cc_delta, current_soc_full, info->soca->rsoc_limit);
+#endif
+
+ if(POWER_SUPPLY_STATUS_FULL == info->soca->chg_status)
+ {
+ info->soca->displayed_soc += 13 * 3000 / fa_cap;
+ } else {
+ ibat_soc_base = 10000 - (RICOH61x_IBAT_TABLE_NUM - 1) * 100 - 50;
+ if (ibat_table[0] < info->soca->Ibat_ave) {
+ if (ibat_soc_base < info->soca->displayed_soc){
+ ibat_soc = ibat_soc_base;
+ } else {
+ ibat_soc = info->soca->displayed_soc;
+ }
+ printk(KERN_INFO "PMU: %s IBAT= %d: ibat_table[%d%%]= %d: ibat_soc= %d ************\n",
+ __func__, info->soca->Ibat_ave, (100 - RICOH61x_IBAT_TABLE_NUM + 1), ibat_table[0], ibat_soc);
+ } else if (ibat_table[RICOH61x_IBAT_TABLE_NUM-1] >= info->soca->Ibat_ave) {
+ ibat_soc = 9950;
+ printk(KERN_INFO "PMU: %s IBAT= %d: ibat_table[100%%]= %d: ibat_soc= %d ************\n",
+ __func__, info->soca->Ibat_ave, ibat_table[RICOH61x_IBAT_TABLE_NUM-1], ibat_soc);
+ } else {
+ for (i = 1; i <= (RICOH61x_IBAT_TABLE_NUM-1); i++) {
+ if(ibat_table[i] <= info->soca->Ibat_ave) {
+ ibat_soc = Calc_Linear_Interpolation(
+ (i-1) * 100, ibat_table[i-1], i * 100,
+ ibat_table[i], info->soca->Ibat_ave);
+ ibat_soc += ibat_soc_base;
+
+#ifdef LTS_DEBUG
+ printk(KERN_INFO "PMU: %s IBAT= %d: ibat_table[%d%%]= %d, ibat_table[%d%%]= %d: ibat_soc= %d: ************\n",
+ __func__, info->soca->Ibat_ave, (100 - RICOH61x_IBAT_TABLE_NUM + i), ibat_table[i-1],
+ (100 - RICOH61x_IBAT_TABLE_NUM + 1 + i), ibat_table[i], ibat_soc);
+#endif
+ break;
+ }
+ }
+ }
+
+ // full_rate = 100 * (100 - DSOC) * (100 - DSOC) / ((100 - IBAT_SOC) * (100 - IBAT_SOC))
+ full_rate = (long)(100 * (10000 - info->soca->displayed_soc)) / (10000 - ibat_soc);
+ full_rate = full_rate * (10000 - info->soca->displayed_soc) / (10000 - ibat_soc);
+
+ /* Adjust parameters */
+ full_rate_org = full_rate;
+ full_rate_max = 140;
+ full_rate_min = 30;
+
+ if (ibat_soc >= 9450) {
+ full_rate_max = 140 + (ibat_soc - 9450) / 2;
+ }
+
+ full_rate = min(full_rate_max, max(full_rate_min, full_rate));
+
+ dsoc_var = info->soca->cc_delta * (int)full_rate / 100;
+ dsoc_var_org = dsoc_var;
+ if (info->soca->cc_delta <= 0) {
+ dsoc_var = 0;
+ } else {
+ dsoc_var = max(3, dsoc_var);
+ }
+
+#ifdef LTS_DEBUG
+ printk(KERN_INFO "PMU: cc_delta= %d: ibat_soc= %d: full_rate= %ld: %ld: dsoc_var= %d: %d: IBAT= %d: DSOC= %d: RSOC= %d:\n",
+ info->soca->cc_delta, ibat_soc, full_rate_org, full_rate, dsoc_var_org, dsoc_var,
+ info->soca->Ibat_ave, (info->soca->displayed_soc + dsoc_var), info->soca->last_soc);
+#endif
+
+ info->soca->displayed_soc
+ = info->soca->displayed_soc + dsoc_var;
+ }
+ info->soca->displayed_soc
+ = min(10000, info->soca->displayed_soc);
+ info->soca->displayed_soc = max(0, info->soca->displayed_soc);
+
+ if (info->soca->displayed_soc >= 9890) {
+ info->soca->displayed_soc = 99 * 100;
+ }
+ }
+ }
+ } else {
+ info->soca->full_reset_count = 0;
+ }
+ } else { /* discharging */
+ if (info->soca->displayed_soc >= 9950) {
+ if (info->soca->Ibat_ave <= -1 * RICOH61x_REL1_SEL_VALUE) {
+ if ((calculated_ocv < (get_OCV_voltage(info, 9, USING) + (get_OCV_voltage(info, 10, USING) - get_OCV_voltage(info, 9, USING))*3/10))
+ || ((info->soca->soc_full - info->soca->soc) > 200)) {
+
+ g_full_flag = 0;
+ info->soca->full_reset_count = 0;
+ info->soca->displayed_soc = 100 * 100;
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->last_soc = info->soca->soc;
+ info->soca->soc_delta = 0;
+ info->soca->temp_cc_delta_cap = 0;
+ } else {
+ info->soca->displayed_soc = 100 * 100;
+ }
+ } else { /* into relaxation state */
+ ricoh61x_read(info->dev->parent, CHGSTATE_REG, &reg_val);
+ if (reg_val & 0xc0) {
+ info->soca->displayed_soc = 100 * 100;
+ } else {
+ g_full_flag = 0;
+ info->soca->full_reset_count = 0;
+ info->soca->displayed_soc = 100 * 100;
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->last_soc = info->soca->soc;
+ info->soca->soc_delta = 0;
+ info->soca->temp_cc_delta_cap = 0;
+ }
+ }
+ } else {
+ g_full_flag = 0;
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->soc_delta = 0;
+ info->soca->full_reset_count = 0;
+ info->soca->last_soc = info->soca->soc;
+ info->soca->temp_cc_delta_cap = 0;
+ }
+ }
+ } else if (RICOH61x_SOCA_LOW_VOL == info->soca->status) {
+
+ mainFlowOfLowVoltage(info);
+ }
+
+ if (RICOH61x_SOCA_DISP == info->soca->status) {
+
+ info->soca->soc = calc_capacity_2(info);
+
+ soc_round = (info->soca->soc + 50) / 100;
+ last_soc_round = (info->soca->last_soc + 50) / 100;
+ last_disp_round = (info->soca->displayed_soc + 50) / 100;
+
+ info->soca->soc_delta =
+ info->soca->soc_delta + (info->soca->soc - info->soca->last_soc);
+
+ 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 = RICOH61x_SOCA_STABLE;
+ delay_flag = 1;
+ } else if (info->soca->Ibat_ave > 0) {
+ if ((0 == info->soca->jt_limit) ||
+ (POWER_SUPPLY_STATUS_FULL != info->soca->chg_status)) {
+ /* Charge */
+ if (last_disp_round < soc_round) {
+ /* Case 1 : Charge, Display < SOC */
+ if (info->soca->soc_delta >= 100) {
+ info->soca->displayed_soc
+ = last_disp_round * 100 + 50;
+ info->soca->soc_delta -= 100;
+ if (info->soca->soc_delta >= 100)
+ delay_flag = 1;
+ } else {
+ info->soca->displayed_soc += 25;
+ disp_dec = info->soca->displayed_soc % 100;
+ if ((50 <= disp_dec) && (disp_dec <= 74))
+ info->soca->soc_delta = 0;
+ }
+ if ((info->soca->displayed_soc + 50)/100
+ >= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH61x_SOCA_STABLE;
+ delay_flag = 1;
+ }
+ } else if (last_disp_round > soc_round) {
+ /* Case 2 : Charge, Display > SOC */
+ if (info->soca->soc_delta >= 300) {
+ info->soca->displayed_soc += 100;
+ info->soca->soc_delta -= 300;
+ }
+ if ((info->soca->displayed_soc + 50)/100
+ <= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH61x_SOCA_STABLE;
+ delay_flag = 1;
+ }
+ }
+ } else {
+ info->soca->soc_delta = 0;
+ }
+ } else {
+ /* Dis-Charge */
+ if (last_disp_round > soc_round) {
+ /* Case 3 : Dis-Charge, Display > SOC */
+ if (info->soca->soc_delta <= -100) {
+ info->soca->displayed_soc
+ = last_disp_round * 100 - 75;
+ info->soca->soc_delta += 100;
+ if (info->soca->soc_delta <= -100)
+ delay_flag = 1;
+ } else {
+ info->soca->displayed_soc -= 25;
+ disp_dec = info->soca->displayed_soc % 100;
+ if ((25 <= disp_dec) && (disp_dec <= 49))
+ info->soca->soc_delta = 0;
+ }
+ if ((info->soca->displayed_soc + 50)/100
+ <= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH61x_SOCA_STABLE;
+ delay_flag = 1;
+ }
+ } else if (last_disp_round < soc_round) {
+ /* Case 4 : Dis-Charge, Display < SOC */
+ if (info->soca->soc_delta <= -300) {
+ info->soca->displayed_soc -= 100;
+ info->soca->soc_delta += 300;
+ }
+ if ((info->soca->displayed_soc + 50)/100
+ >= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH61x_SOCA_STABLE;
+ delay_flag = 1;
+ }
+ }
+ }
+ } else if (RICOH61x_SOCA_UNSTABLE == info->soca->status) {
+ /* caluc 95% ocv */
+ temp_ocv = get_OCV_voltage(info, 10, USING) -
+ (get_OCV_voltage(info, 10, USING) - get_OCV_voltage(info, 9, USING))/2;
+
+ if(g_full_flag == 1){ /* for issue 1 solution start*/
+ info->soca->status = RICOH61x_SOCA_FULL;
+ info->soca->last_soc_full = 0;
+ err = reset_FG_process(info);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ goto end_flow;
+ }else if ((POWER_SUPPLY_STATUS_FULL == info->soca->chg_status)
+ && (calculated_ocv > temp_ocv)) {
+ info->soca->status = RICOH61x_SOCA_FULL;
+ g_full_flag = 0;
+ info->soca->last_soc_full = 0;
+ err = reset_FG_process(info);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto end_flow;
+ } else if (info->soca->Ibat_ave >= -12) {
+ /* for issue1 solution end */
+ /* check Full state or not*/
+ if ((calculated_ocv > (get_OCV_voltage(info, 9, USING) + (get_OCV_voltage(info, 10, USING) - get_OCV_voltage(info, 9, USING))*7/10))
+ || (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status)
+ || (info->soca->displayed_soc > 9850))
+ {
+ info->soca->status = RICOH61x_SOCA_FULL;
+ g_full_flag = 0;
+ info->soca->last_soc_full = 0;
+ err = reset_FG_process(info);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto end_flow;
+ } else if ((calculated_ocv > (get_OCV_voltage(info, 9, USING)))
+ && (info->soca->Ibat_ave < 300))
+ {
+ info->soca->status = RICOH61x_SOCA_FULL;
+ g_full_flag = 0;
+ info->soca->last_soc_full = 0;
+ err = reset_FG_process(info);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto end_flow;
+ }
+ }
+
+ info->soca->soc = info->soca->init_pswr * 100;
+
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 0);
+ if (err < 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;
+ if (displayed_soc_temp < 0)
+ displayed_soc_temp = 0;
+ displayed_soc_temp
+ = min(9850, displayed_soc_temp);
+ displayed_soc_temp = max(0, displayed_soc_temp);
+
+ info->soca->displayed_soc = displayed_soc_temp;
+
+ } else if (RICOH61x_SOCA_FG_RESET == info->soca->status) {
+ /* No update */
+ } else if (RICOH61x_SOCA_START == info->soca->status) {
+
+ err = measure_Ibatt_FG(info, &Ibat);
+ err = measure_vbatt_FG(info, &Vbat);
+ err = measure_vsys_ADC(info, &Vsys);
+
+ info->soca->Ibat_ave = Ibat;
+ info->soca->Vbat_ave = Vbat;
+ info->soca->Vsys_ave = Vsys;
+
+ err = check_jeita_status(info, &is_jeita_updated);
+ is_jeita_updated = false;
+ if (err < 0) {
+ dev_err(info->dev, "Error in updating JEITA %d\n", err);
+ }
+ err = ricoh61x_read(info->dev->parent, PSWR_REG, &val_pswr);
+ val_pswr &= 0x7f;
+
+ if (info->first_pwon) {
+ displayed_soc_temp = val_pswr * 100;
+
+ info->soca->soc = calc_capacity(info) * 100;
+
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+
+ //get DSOC temp value
+ if (displayed_soc_temp == 0) { //initial power on or some error case
+
+ displayed_soc_temp = info->soca->soc;
+ printk(KERN_INFO "PMU: %s : initial power on\n",__func__);
+
+ } else if ((Ibat > 0)
+ && (displayed_soc_temp < info->soca->soc)){ //charge and poff_DSOC < RSOC
+ displayed_soc_temp = info->soca->soc;
+ printk(KERN_INFO "PMU: %s : normal case Ibat is %dmA, poffDSOC is %d, RSOC is %dn\n"
+ ,__func__, Ibat, val_pswr*100, info->soca->soc);
+ } else if ((info->soca->cc_delta <= 0)
+ && (displayed_soc_temp > info->soca->soc)){ //discharge and poff_DSOC > RSOC
+
+ displayed_soc_temp = info->soca->soc;
+ printk(KERN_INFO "PMU: %s : normal case cc delta is %dmA, poffDSOC is %d, RSOC is %dn\n"
+ ,__func__, info->soca->cc_delta, val_pswr*100, info->soca->soc);
+
+ } else if ((info->soca->cc_delta > 0)
+ && (displayed_soc_temp < info->soca->soc)){ //charge and poff_DSOC < RSOC
+ displayed_soc_temp = info->soca->soc;
+ printk(KERN_INFO "PMU: %s : normal case cc delta is %dmA, poffDSOC is %d, RSOC is %dn\n"
+ ,__func__, info->soca->cc_delta, val_pswr*100, info->soca->soc);
+ } else {
+ //displayed_soc_temp = displayed_soc_temp;
+ printk(KERN_INFO "PMU: %s : error case cc delta is %dmA, poffDSOC is %d, RSOC is %dn\n"
+ ,__func__, info->soca->cc_delta, val_pswr*100, info->soca->soc);
+ }
+
+ //val = (info->soca->soc + 50)/100;
+ val = (displayed_soc_temp + 50)/100;
+ val &= 0x7f;
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ info->soca->init_pswr = val;
+ g_soc = val;
+ set_current_time2register(info);
+
+ if (0 == info->soca->jt_limit) {
+ check_charge_status_2(info, displayed_soc_temp);
+ } else {
+ info->soca->displayed_soc = displayed_soc_temp;
+ }
+ if (Ibat < 0) {
+ initSettingOfLowVoltage(info);
+ info->soca->status = RICOH61x_SOCA_LOW_VOL;
+ } else {
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->soc_delta = 0;
+ info->soca->last_soc = displayed_soc_temp;
+ }
+
+ } else if (g_fg_on_mode && (val_pswr == 0x7f)) {
+ info->soca->soc = calc_capacity(info) * 100;
+ if (0 == info->soca->jt_limit) {
+ check_charge_status_2(info, info->soca->soc);
+ } else {
+ info->soca->displayed_soc = info->soca->soc;
+ }
+ info->soca->last_soc = info->soca->soc;
+ info->soca->status = RICOH61x_SOCA_STABLE;
+ } else {
+ info->soca->soc = val_pswr * 100;
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in reading PSWR_REG %d\n", err);
+ info->soca->soc
+ = calc_capacity(info) * 100;
+ }
+
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 2);
+ if (err < 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 / 100) * 100;
+
+ displayed_soc_temp
+ = min(10000, displayed_soc_temp);
+ if (displayed_soc_temp <= 100) {
+ displayed_soc_temp = 100;
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ }
+
+ printk(KERN_INFO "PMU: %s : dsoc_temp(%d), soc(%d), cc_delta(%d)\n",
+ __func__, displayed_soc_temp, info->soca->soc, info->soca->cc_delta);
+ printk(KERN_INFO "PMU: %s : status(%d), rsoc_ready_flag(%d)\n",
+ __func__, info->soca->status, info->soca->rsoc_ready_flag);
+
+ if (0 == info->soca->jt_limit) {
+ check_charge_status_2(info, displayed_soc_temp);
+ } else {
+ info->soca->displayed_soc = displayed_soc_temp;
+ }
+
+ val = (displayed_soc_temp + 50)/100;
+ val &= 0x7f;
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ info->soca->init_pswr = val;
+ g_soc = val;
+ set_current_time2register(info);
+
+ info->soca->last_soc = calc_capacity_2(info);
+
+ if(info->soca->rsoc_ready_flag == 0) {
+
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->soc_delta = 0;
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU FG_RESET : %s : initial dsoc is %d\n",__func__,info->soca->displayed_soc);
+#endif
+ } else if (Ibat < 0) {
+ initSettingOfLowVoltage(info);
+ info->soca->status = RICOH61x_SOCA_LOW_VOL;
+ } else {
+ info->soca->status = RICOH61x_SOCA_DISP;
+ info->soca->soc_delta = 0;
+ }
+ }
+ }
+end_flow:
+ /* keep DSOC = 1 when Vbat is over 3.4V*/
+ if( info->fg_poff_vbat != 0) {
+ if (info->soca->zero_flg == 1) {
+ if ((info->soca->Ibat_ave >= 0)
+ || (info->soca->Vbat_ave >= (info->fg_poff_vbat+100)*1000)) {
+ info->soca->zero_flg = 0;
+ } else {
+ info->soca->displayed_soc = 0;
+ }
+ } else if (info->soca->displayed_soc < 50) {
+ if (info->soca->Vbat_ave < 2000*1000) { /* error value */
+ info->soca->displayed_soc = 100;
+ } else if (info->soca->Vbat_ave < info->fg_poff_vbat*1000) {
+ info->soca->displayed_soc = 0;
+ info->soca->zero_flg = 1;
+ } else {
+ info->soca->displayed_soc = 100;
+ }
+ }
+ }
+
+ if (g_fg_on_mode
+ && (info->soca->status == RICOH61x_SOCA_STABLE)) {
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, 0x7f);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ g_soc = 0x7F;
+ set_current_time2register(info);
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ } else if (((RICOH61x_SOCA_UNSTABLE != info->soca->status)
+ && (info->soca->rsoc_ready_flag != 0))
+ || (RICOH61x_SOCA_LOW_VOL == info->soca->status)){
+ if ((info->soca->displayed_soc + 50)/100 <= 1) {
+ val = 1;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ }
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = val;
+ set_current_time2register(info);
+
+ info->soca->init_pswr = val;
+
+ if(RICOH61x_SOCA_LOW_VOL != info->soca->status)
+ {
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ printk(KERN_INFO "PMU: %s Full-Clear CC, PSWR(%d)\n",
+ __func__, val);
+ }
+ } else { /* Case of UNSTABLE STATE */
+ if ((info->soca->displayed_soc + 50)/100 <= 1) {
+ val = 1;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ }
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = val;
+ set_current_time2register(info);
+
+ err = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 2);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+
+ val = info->soca->init_pswr + (info->soca->cc_delta/100);
+ val = min(100, val);
+ val = max(1, val);
+
+ info->soca->init_pswr = val;
+
+ info->soca->last_cc_rrf0 = info->soca->cc_delta%100;
+
+ printk(KERN_INFO "PMU: %s Half-Clear CC, init_pswr(%d), cc_delta(%d)\n",
+ __func__, info->soca->init_pswr, info->soca->cc_delta);
+
+ }
+
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU:STATUS= %d: IBAT= %d: VSYS= %d: VBAT= %d: DSOC= %d: RSOC= %d: cc_delta=%d: rrf= %d\n",
+ info->soca->status, info->soca->Ibat_ave, info->soca->Vsys_ave, info->soca->Vbat_ave,
+ info->soca->displayed_soc, info->soca->soc, info->soca->cc_delta, info->soca->rsoc_ready_flag);
+#endif
+
+// printk("PMU AGE*STATUS * %d*IBAT*%d*VSYS*%d*VBAT*%d*DSOC*%d*RSOC*%d*-------\n",
+// info->soca->status, info->soca->Ibat_ave, info->soca->Vsys_ave, info->soca->Vbat_ave,
+// info->soca->displayed_soc, info->soca->soc);
+
+#ifdef DISABLE_CHARGER_TIMER
+ /* clear charger timer */
+ if ( info->soca->chg_status == POWER_SUPPLY_STATUS_CHARGING ) {
+ err = ricoh61x_read(info->dev->parent, TIMSET_REG, &val);
+ if (err < 0)
+ dev_err(info->dev,
+ "Error in read TIMSET_REG%d\n", err);
+ /* to check bit 0-1 */
+ val2 = val & 0x03;
+
+ if (val2 == 0x02){
+ /* set rapid timer 240 -> 300 */
+ err = ricoh61x_set_bits(info->dev->parent, TIMSET_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ }
+ } else {
+ /* set rapid timer 300 -> 240 */
+ err = ricoh61x_clr_bits(info->dev->parent, TIMSET_REG, 0x01);
+ err = ricoh61x_set_bits(info->dev->parent, TIMSET_REG, 0x02);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ }
+ }
+ }
+#endif
+
+ if (0 == info->soca->ready_fg)
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_FG_RESET_TIME * HZ);
+ else if (delay_flag == 1)
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_DELAY_TIME * HZ);
+ else if ((RICOH61x_SOCA_DISP == info->soca->status)
+ && (info->soca->Ibat_ave > 0))
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_DISP_CHG_UPDATE_TIME * HZ);
+ else if ((info->soca->hurry_up_flg == 1) && (RICOH61x_SOCA_LOW_VOL == info->soca->status))
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_LOW_VOL_DOWN_TIME * HZ);
+ else
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_DISPLAY_UPDATE_TIME * HZ);
+
+ mutex_unlock(&info->lock);
+
+ if((true == is_jeita_updated)
+ || (info->soca->last_displayed_soc/100 != (info->soca->displayed_soc+50)/100))
+ power_supply_changed(&info->battery);
+
+ info->soca->last_displayed_soc = info->soca->displayed_soc+50;
+
+ return;
+}
+
+static void ricoh61x_stable_charge_countdown_work(struct work_struct *work)
+{
+ int ret;
+ int max = 0;
+ int min = 100;
+ int i;
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, charge_stable_work.work);
+
+ if (info->entry_factory_mode)
+ return;
+
+ mutex_lock(&info->lock);
+ if (RICOH61x_SOCA_FG_RESET == info->soca->status)
+ info->soca->ready_fg = 1;
+
+ if (2 <= info->soca->stable_count) {
+ if (3 == info->soca->stable_count
+ && RICOH61x_SOCA_FG_RESET == info->soca->status) {
+ ret = reset_FG_process(info);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ }
+ info->soca->stable_count = info->soca->stable_count - 1;
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH61x_FG_STABLE_TIME * HZ / 10);
+ } else if (0 >= info->soca->stable_count) {
+ /* Finished queue, ignore */
+ } else if (1 == info->soca->stable_count) {
+ if (RICOH61x_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,
+ RICOH61x_FG_STABLE_TIME * HZ / 10);
+ mutex_unlock(&info->lock);
+ return;
+ }
+ /* Do reset setting */
+ ret = reset_FG_process(info);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ info->soca->status = RICOH61x_SOCA_FG_RESET;
+
+ /* Delay for addition Reset Time (6s) */
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH61x_FG_RESET_TIME*HZ);
+ } else if (RICOH61x_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)
+ < RICOH61x_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 = reset_FG_process(info);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ /* Delay for addition Reset Time (6s) */
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH61x_FG_RESET_TIME*HZ);
+ }
+ /* Finished queue From now, select FG as result; */
+ } else if (RICOH61x_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 = RICOH61x_SOCA_DISP;
+ info->soca->soc_delta = 0;
+
+ }
+ mutex_unlock(&info->lock);
+ return;
+}
+
+static void ricoh61x_charge_monitor_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, charge_monitor_work.work);
+
+ get_power_supply_status(info);
+
+ if (POWER_SUPPLY_STATUS_DISCHARGING == info->soca->chg_status
+ || POWER_SUPPLY_STATUS_NOT_CHARGING == info->soca->chg_status) {
+ switch (info->soca->dischg_state) {
+ case 0:
+ info->soca->dischg_state = 1;
+ break;
+ case 1:
+ info->soca->dischg_state = 2;
+ break;
+
+ case 2:
+ default:
+ break;
+ }
+ } else {
+ info->soca->dischg_state = 0;
+ }
+
+ queue_delayed_work(info->monitor_wqueue, &info->charge_monitor_work,
+ RICOH61x_CHARGE_MONITOR_TIME * HZ);
+
+ return;
+}
+
+static void ricoh61x_get_charge_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, get_charge_work.work);
+
+ int Vbat_temp, Vsys_temp, Ibat_temp;
+ int Vbat_sort[RICOH61x_GET_CHARGE_NUM];
+ int Vsys_sort[RICOH61x_GET_CHARGE_NUM];
+ int Ibat_sort[RICOH61x_GET_CHARGE_NUM];
+ int i, j;
+ int ret;
+
+ mutex_lock(&info->lock);
+
+ for (i = RICOH61x_GET_CHARGE_NUM-1; i > 0; i--) {
+ if (0 == info->soca->chg_count) {
+ info->soca->Vbat[i] = 0;
+ info->soca->Vsys[i] = 0;
+ info->soca->Ibat[i] = 0;
+ } else {
+ info->soca->Vbat[i] = info->soca->Vbat[i-1];
+ info->soca->Vsys[i] = info->soca->Vsys[i-1];
+ info->soca->Ibat[i] = info->soca->Ibat[i-1];
+ }
+ }
+
+ ret = measure_vbatt_FG(info, &info->soca->Vbat[0]);
+ ret = measure_vsys_ADC(info, &info->soca->Vsys[0]);
+ ret = measure_Ibatt_FG(info, &info->soca->Ibat[0]);
+
+ info->soca->chg_count++;
+
+ if (RICOH61x_GET_CHARGE_NUM != info->soca->chg_count) {
+ queue_delayed_work(info->monitor_wqueue, &info->get_charge_work,
+ RICOH61x_CHARGE_CALC_TIME * HZ);
+ mutex_unlock(&info->lock);
+ return ;
+ }
+
+ for (i = 0; i < RICOH61x_GET_CHARGE_NUM; i++) {
+ Vbat_sort[i] = info->soca->Vbat[i];
+ Vsys_sort[i] = info->soca->Vsys[i];
+ Ibat_sort[i] = info->soca->Ibat[i];
+ }
+
+ Vbat_temp = 0;
+ Vsys_temp = 0;
+ Ibat_temp = 0;
+ for (i = 0; i < RICOH61x_GET_CHARGE_NUM - 1; i++) {
+ for (j = RICOH61x_GET_CHARGE_NUM - 1; j > i; j--) {
+ if (Vbat_sort[j - 1] > Vbat_sort[j]) {
+ Vbat_temp = Vbat_sort[j];
+ Vbat_sort[j] = Vbat_sort[j - 1];
+ Vbat_sort[j - 1] = Vbat_temp;
+ }
+ if (Vsys_sort[j - 1] > Vsys_sort[j]) {
+ Vsys_temp = Vsys_sort[j];
+ Vsys_sort[j] = Vsys_sort[j - 1];
+ Vsys_sort[j - 1] = Vsys_temp;
+ }
+ if (Ibat_sort[j - 1] > Ibat_sort[j]) {
+ Ibat_temp = Ibat_sort[j];
+ Ibat_sort[j] = Ibat_sort[j - 1];
+ Ibat_sort[j - 1] = Ibat_temp;
+ }
+ }
+ }
+
+ Vbat_temp = 0;
+ Vsys_temp = 0;
+ Ibat_temp = 0;
+ for (i = 3; i < RICOH61x_GET_CHARGE_NUM-3; i++) {
+ Vbat_temp = Vbat_temp + Vbat_sort[i];
+ Vsys_temp = Vsys_temp + Vsys_sort[i];
+ Ibat_temp = Ibat_temp + Ibat_sort[i];
+ }
+ Vbat_temp = Vbat_temp / (RICOH61x_GET_CHARGE_NUM - 6);
+ Vsys_temp = Vsys_temp / (RICOH61x_GET_CHARGE_NUM - 6);
+ Ibat_temp = Ibat_temp / (RICOH61x_GET_CHARGE_NUM - 6);
+
+ if (0 == info->soca->chg_count) {
+ queue_delayed_work(info->monitor_wqueue, &info->get_charge_work,
+ RICOH61x_CHARGE_UPDATE_TIME * HZ);
+ mutex_unlock(&info->lock);
+ return;
+ } else {
+ info->soca->Vbat_ave = Vbat_temp;
+ info->soca->Vsys_ave = Vsys_temp;
+ info->soca->Ibat_ave = Ibat_temp;
+ }
+
+ info->soca->chg_count = 0;
+ queue_delayed_work(info->monitor_wqueue, &info->get_charge_work,
+ RICOH61x_CHARGE_UPDATE_TIME * HZ);
+ mutex_unlock(&info->lock);
+ return;
+}
+
+/* Initial setting of FuelGauge SOCA function */
+static int ricoh61x_init_fgsoca(struct ricoh61x_battery_info *info)
+{
+ int i;
+ int err;
+ uint8_t val;
+
+ for (i = 0; i <= 10; i = i+1) {
+ info->soca->ocv_table[i] = get_OCV_voltage(info, i, USING);
+ printk(KERN_INFO "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 = ricoh61x_read(info->dev->parent, CHGISET_REG, &val);
+ if (err < 0)
+ dev_err(info->dev,
+ "Error in read CHGISET_REG%d\n", err);
+
+ err = ricoh61x_write(info->dev->parent, CHGISET_REG, 0);
+ if (err < 0)
+ dev_err(info->dev,
+ "Error in writing CHGISET_REG%d\n", err);
+ /* msleep(1000); */
+
+ if (!info->entry_factory_mode) {
+ err = ricoh61x_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ }
+
+ info->soca->rsoc_ready_flag = 1;
+
+ /* msleep(6000); */
+
+ err = ricoh61x_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, USING) * 1000 / 512
+ * 5000 / 4095;
+ info->soca->n_cap = get_OCV_init_Data(info, 11, USING);
+
+
+ info->soca->displayed_soc = 0;
+ info->soca->last_displayed_soc = 0;
+ info->soca->suspend_soc = 0;
+ info->soca->suspend_full_flg = false;
+ info->soca->ready_fg = 0;
+ info->soca->soc_delta = 0;
+ info->soca->full_reset_count = 0;
+ info->soca->soc_full = 0;
+ info->soca->fc_cap = 0;
+ info->soca->status = RICOH61x_SOCA_START;
+ /* stable count down 11->2, 1: reset; 0: Finished; */
+ info->soca->stable_count = 11;
+ info->soca->dischg_state = 0;
+ info->soca->Vbat_ave = 0;
+ info->soca->Vbat_old = 0;
+ info->soca->Vsys_ave = 0;
+ info->soca->Ibat_ave = 0;
+ info->soca->chg_count = 0;
+ info->soca->hurry_up_flg = 0;
+ info->soca->re_cap_old = 0;
+ info->soca->jt_limit = 0;
+ info->soca->zero_flg = 0;
+ info->soca->cc_cap_offset = 0;
+ info->soca->sus_cc_cap_offset = 0;
+ info->soca->last_soc_full = 0;
+ info->soca->rsoc_limit = 0;
+ info->soca->last_cc_rrf0 = 0;
+ info->soca->last_cc_delta_cap = 0;
+ info->soca->last_cc_delta_cap_mas = 0;
+ info->soca->temp_cc_delta_cap_mas = 0;
+ info->soca->temp_cc_delta_cap = 0;
+
+ info->soca->store_fl_current = RICOH61x_FL_CURRENT_DEF;
+ info->soca->store_slp_state = 0;
+ info->soca->store_sus_current = RICOH61x_SUS_CURRENT_DEF;
+ info->soca->store_hiber_current = RICOH61x_HIBER_CURRENT_DEF;
+
+ for (i = 0; i < 11; i++) {
+ info->soca->ocv_table_low[i] = 0;
+ }
+
+ for (i = 0; i < RICOH61x_GET_CHARGE_NUM; i++) {
+ info->soca->Vbat[i] = 0;
+ info->soca->Vsys[i] = 0;
+ info->soca->Ibat[i] = 0;
+ }
+
+ /*********************************/
+ //fl_level = RICOH61x_FL_LEVEL_DEF;
+ //fl_current = RICOH61x_FL_CURRENT_DEF;
+ //slp_state = 0;
+ //idle_current = RICOH61x_IDLE_CURRENT_DEF;
+ //sus_current = RICOH61x_SUS_CURRENT_DEF;
+ //hiber_current = RICOH61x_HIBER_CURRENT_DEF;
+ //bat_alert_req_flg = 0;
+#ifdef STANDBY_MODE_DEBUG
+ multiple_sleep_mode = 0;
+#endif
+ /*********************************/
+
+#ifdef ENABLE_FG_KEEP_ON_MODE
+ g_fg_on_mode = 1;
+ info->soca->rsoc_ready_flag = 1;
+#else
+ g_fg_on_mode = 0;
+#endif
+
+
+ /* Start first Display job */
+ if(info->first_pwon) {
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_FG_RESET_TIME*HZ);
+ }else {
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH61x_MAIN_START_TIME*HZ);
+ }
+
+ /* Start first Waiting stable job */
+ queue_delayed_work(info->monitor_wqueue, &info->charge_stable_work,
+ RICOH61x_FG_STABLE_TIME*HZ/10);
+
+ queue_delayed_work(info->monitor_wqueue, &info->charge_monitor_work,
+ RICOH61x_CHARGE_MONITOR_TIME * HZ);
+
+ queue_delayed_work(info->monitor_wqueue, &info->get_charge_work,
+ RICOH61x_CHARGE_MONITOR_TIME * HZ);
+ if (info->jt_en) {
+ if (info->jt_hw_sw) {
+ /* Enable JEITA function supported by H/W */
+ err = ricoh61x_set_bits(info->dev->parent, CHGCTL1_REG, 0x04);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ } else {
+ /* Disable JEITA function supported by H/W */
+ err = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x04);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ queue_delayed_work(info->monitor_wqueue, &info->jeita_work,
+ RICOH61x_FG_RESET_TIME * HZ);
+ }
+ } else {
+ /* Disable JEITA function supported by H/W */
+ err = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x04);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ if (0xff != info->ch_ilim_adp && (info->ch_ilim_adp <= 0x1D)) {
+ /* REGISET1:(0xB6) setting */
+ err = ricoh61x_write(info->dev->parent, REGISET1_REG, info->ch_ilim_adp);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing REGISET1_REG %d\n",err);
+ if (0xff != info->jt_ichg_h && (info->jt_ichg_h <= 0x1D)) {
+ /* CHGISET:(0xB8) setting */
+ err = ricoh61x_write(info->dev->parent, CHGISET_REG, info->jt_ichg_h);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing CHGISET_REG %d\n",err);
+ }
+ }
+ }
+
+ printk(KERN_INFO "PMU: %s : * Rbat = %d mOhm n_cap = %d mAH\n",
+ __func__, info->soca->Rbat, info->soca->n_cap);
+ return 1;
+}
+#endif
+
+static void ricoh61x_changed_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, changed_work.work);
+
+ printk(KERN_INFO "PMU: %s\n", __func__);
+ power_supply_changed(&info->battery);
+
+ return;
+}
+
+static int check_jeita_status(struct ricoh61x_battery_info *info, bool *is_jeita_updated)
+/* JEITA Parameter settings
+*
+* VCHG
+* |
+* jt_vfchg_h~+~~~~~~~~~~~~~~~~~~~+
+* | |
+* jt_vfchg_l-| - - - - - - - - - +~~~~~~~~~~+
+* | Charge area + |
+* -------0--+-------------------+----------+--- Temp
+* ! +
+* ICHG
+* | +
+* jt_ichg_h-+ - -+~~~~~~~~~~~~~~+~~~~~~~~~~+
+* + | + |
+* jt_ichg_l-+~~~~+ Charge area |
+* | + + |
+* 0--+----+--------------+----------+--- Temp
+* 0 jt_temp_l jt_temp_h 55
+*/
+{
+ int temp;
+ int err = 0;
+ int vfchg;
+ uint8_t chgiset_org;
+ uint8_t batset2_org;
+ uint8_t set_vchg_h, set_vchg_l;
+ uint8_t set_ichg_h, set_ichg_l;
+
+ *is_jeita_updated = false;
+ /* No execute if JEITA disabled */
+ if (!info->jt_en || info->jt_hw_sw)
+ return 0;
+
+ /* Check FG Reset */
+ if (info->soca->ready_fg) {
+ temp = get_battery_temp_2(info) / 10;
+ } else {
+ printk(KERN_INFO "JEITA: %s *** cannot update by resetting FG ******\n", __func__);
+ goto out;
+ }
+
+ /* Read BATSET2 */
+ err = ricoh61x_read(info->dev->parent, BATSET2_REG, &batset2_org);
+ if (err < 0) {
+ dev_err(info->dev, "Error in readng the battery setting register\n");
+ goto out;
+ }
+ vfchg = (batset2_org & 0x70) >> 4;
+ batset2_org &= 0x8F;
+
+ /* Read CHGISET */
+ err = ricoh61x_read(info->dev->parent, CHGISET_REG, &chgiset_org);
+ if (err < 0) {
+ dev_err(info->dev, "Error in readng the chrage setting register\n");
+ goto out;
+ }
+ chgiset_org &= 0xC0;
+
+ set_ichg_h = (uint8_t)(chgiset_org | info->jt_ichg_h);
+ set_ichg_l = (uint8_t)(chgiset_org | info->jt_ichg_l);
+
+ set_vchg_h = (uint8_t)((info->jt_vfchg_h << 4) | batset2_org);
+ set_vchg_l = (uint8_t)((info->jt_vfchg_l << 4) | batset2_org);
+
+ printk(KERN_INFO "PMU: %s *** Temperature: %d, vfchg: %d, SW status: %d, chg_status: %d ******\n",
+ __func__, temp, vfchg, info->soca->status, info->soca->chg_status);
+
+ if (temp <= 0 || 55 <= temp) {
+ /* 1st and 5th temperature ranges (~0, 55~) */
+ printk(KERN_INFO "PMU: %s *** Temp(%d) is out of 0-55 ******\n", __func__, temp);
+ err = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+ info->soca->jt_limit = 0;
+ *is_jeita_updated = true;
+ } else if (temp < info->jt_temp_l) {
+ /* 2nd temperature range (0~12) */
+ if (vfchg != info->jt_vfchg_h) {
+ printk(KERN_INFO "PMU: %s *** 0<Temp<12, update to vfchg=%d ******\n",
+ __func__, info->jt_vfchg_h);
+ err = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+
+ /* set VFCHG/VRCHG */
+ err = ricoh61x_write(info->dev->parent,
+ BATSET2_REG, set_vchg_h);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the battery setting register\n");
+ goto out;
+ }
+ info->soca->jt_limit = 0;
+ *is_jeita_updated = true;
+ } else
+ printk(KERN_INFO "PMU: %s *** 0<Temp<50, already set vfchg=%d, so no need to update ******\n",
+ __func__, info->jt_vfchg_h);
+
+ /* set ICHG */
+ err = ricoh61x_write(info->dev->parent, CHGISET_REG, set_ichg_l);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the battery setting register\n");
+ goto out;
+ }
+ err = ricoh61x_set_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+ } else if (temp < info->jt_temp_h) {
+ /* 3rd temperature range (12~50) */
+ if (vfchg != info->jt_vfchg_h) {
+ printk(KERN_INFO "PMU: %s *** 12<Temp<50, update to vfchg==%d ******\n", __func__, info->jt_vfchg_h);
+
+ err = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+ /* set VFCHG/VRCHG */
+ err = ricoh61x_write(info->dev->parent,
+ BATSET2_REG, set_vchg_h);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the battery setting register\n");
+ goto out;
+ }
+ info->soca->jt_limit = 0;
+ *is_jeita_updated = true;
+ } else
+ printk(KERN_INFO "PMU: %s *** 12<Temp<50, already set vfchg==%d, so no need to update ******\n",
+ __func__, info->jt_vfchg_h);
+
+ /* set ICHG */
+ err = ricoh61x_write(info->dev->parent, CHGISET_REG, set_ichg_h);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the battery setting register\n");
+ goto out;
+ }
+ err = ricoh61x_set_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+ } else if (temp < 55) {
+ /* 4th temperature range (50~55) */
+ if (vfchg != info->jt_vfchg_l) {
+ printk(KERN_INFO "PMU: %s *** 50<Temp<55, update to vfchg==%d ******\n", __func__, info->jt_vfchg_l);
+
+ err = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+ /* set VFCHG/VRCHG */
+ err = ricoh61x_write(info->dev->parent,
+ BATSET2_REG, set_vchg_l);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the battery setting register\n");
+ goto out;
+ }
+ info->soca->jt_limit = 1;
+ *is_jeita_updated = true;
+ } else
+ printk(KERN_INFO "JEITA: %s *** 50<Temp<55, already set vfchg==%d, so no need to update ******\n",
+ __func__, info->jt_vfchg_l);
+
+ /* set ICHG */
+ err = ricoh61x_write(info->dev->parent, CHGISET_REG, set_ichg_h);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the battery setting register\n");
+ goto out;
+ }
+ err = ricoh61x_set_bits(info->dev->parent, CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto out;
+ }
+ }
+
+ get_power_supply_status(info);
+ printk(KERN_INFO "PMU: %s *** Hope updating value in this timing after checking jeita, chg_status: %d, is_jeita_updated: %d ******\n",
+ __func__, info->soca->chg_status, *is_jeita_updated);
+
+ return 0;
+
+out:
+ printk(KERN_INFO "PMU: %s ERROR ******\n", __func__);
+ return err;
+}
+
+static void ricoh61x_jeita_work(struct work_struct *work)
+{
+ int ret;
+ bool is_jeita_updated = false;
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, jeita_work.work);
+
+ mutex_lock(&info->lock);
+
+ ret = check_jeita_status(info, &is_jeita_updated);
+ if (0 == ret) {
+ queue_delayed_work(info->monitor_wqueue, &info->jeita_work,
+ RICOH61x_JEITA_UPDATE_TIME * HZ);
+ } else {
+ printk(KERN_INFO "PMU: %s *** Call check_jeita_status() in jeita_work, err:%d ******\n",
+ __func__, ret);
+ queue_delayed_work(info->monitor_wqueue, &info->jeita_work,
+ RICOH61x_FG_RESET_TIME * HZ);
+ }
+
+ mutex_unlock(&info->lock);
+
+ if(true == is_jeita_updated)
+ 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 ricoh61x_factory_mode(struct ricoh61x_battery_info *info)
+{
+ int ret = 0;
+ uint8_t val = 0;
+
+ ret = ricoh61x_read(info->dev->parent, RICOH61x_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 = ricoh61x_set_bits(info->dev->parent, CHGCTL1_REG, 0x40);
+
+ 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 ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, factory_mode_work.work);
+
+ int ret = 0;
+ uint8_t val = 0;
+ int chargeCurrent = 0;
+
+ ret = ricoh61x_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) {
+ printk(KERN_INFO "PMU:%s --- No battery !! Enter Factory mode ---\n"
+ , __func__);
+ info->entry_factory_mode = true;
+ /* clear FG_ACC bit */
+ ret = ricoh61x_clr_bits(info->dev->parent, RICOH61x_FG_CTRL, 0x10);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing FG_CTRL\n");
+
+ return; /* Factory Mode */
+ }
+
+ /* Return Normal Mode --> Rapid to Complete State change enable */
+ /* disable the status change from Rapid Charge to Charge Complete */
+
+ ret = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, 0x40);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return;
+ }
+ printk(KERN_INFO "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 void ricoh61x_scaling_OCV_table(struct ricoh61x_battery_info *info, int cutoff_vol, int full_vol, int *start_per, int *end_per)
+{
+ int i, j;
+ int temp;
+ int percent_step;
+ int OCV_percent_new[11];
+
+ /* get ocv table. this table is calculated by Apprication */
+ //printk("PMU : %s : original table\n",__func__);
+ //for (i = 0; i <= 10; i = i+1) {
+ // printk(KERN_INFO "PMU: %s : %d0%% voltage = %d uV\n",
+ // __func__, i, info->soca->ocv_table_def[i]);
+ //}
+ //printk("PMU: %s : cutoff_vol %d full_vol %d\n",
+ // __func__, cutoff_vol,full_vol);
+
+ /* Check Start % */
+ if (info->soca->ocv_table_def[0] > cutoff_vol * 1000) {
+ *start_per = 0;
+ printk("PMU : %s : setting value of cuttoff_vol(%d) is out of range(%d) \n",__func__, cutoff_vol, info->soca->ocv_table_def[0]);
+ } else {
+ for (i = 1; i < 11; i++) {
+ if (info->soca->ocv_table_def[i] >= cutoff_vol * 1000) {
+ /* unit is 0.001% */
+ *start_per = Calc_Linear_Interpolation(
+ (i-1)*1000, info->soca->ocv_table_def[i-1], i*1000,
+ info->soca->ocv_table_def[i], (cutoff_vol * 1000));
+ break;
+ }
+ }
+ }
+
+ /* Check End % */
+ for (i = 1; i < 11; i++) {
+ if (info->soca->ocv_table_def[i] >= full_vol * 1000) {
+ /* unit is 0.001% */
+ *end_per = Calc_Linear_Interpolation(
+ (i-1)*1000, info->soca->ocv_table_def[i-1], i*1000,
+ info->soca->ocv_table_def[i], (full_vol * 1000));
+ break;
+ }
+ }
+
+ /* calc new ocv percent */
+ percent_step = ( *end_per - *start_per) / 10;
+ //printk("PMU : %s : percent_step is %d end per is %d start per is %d\n",__func__, percent_step, *end_per, *start_per);
+
+ for (i = 0; i < 11; i++) {
+ OCV_percent_new[i]
+ = *start_per + 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(
+ info->soca->ocv_table_def[j-1], (j-1)*1000,
+ info->soca->ocv_table_def[j] , j*1000,
+ OCV_percent_new[i]);
+
+ temp = ( (temp/1000) * 4095 ) / 5000;
+
+ battery_init_para[info->num][i*2 + 1] = temp;
+ battery_init_para[info->num][i*2] = temp >> 8;
+
+ break;
+ }
+ }
+ }
+ printk("PMU : %s : new table\n",__func__);
+ for (i = 0; i <= 10; i = i+1) {
+ temp = (battery_init_para[info->num][i*2]<<8)
+ | (battery_init_para[info->num][i*2+1]);
+ /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+ temp = ((temp * 50000 * 10 / 4095) + 5) / 10;
+ printk("PMU : %s : ocv_table %d is %d v\n",__func__, i, temp);
+ }
+
+}
+
+static int ricoh61x_set_OCV_table(struct ricoh61x_battery_info *info)
+{
+ int ret = 0;
+ int i;
+ int full_ocv;
+ int available_cap;
+ int available_cap_ori;
+ int temp;
+ int temp1;
+ int start_per = 0;
+ int end_per = 0;
+ int Rbat;
+ int Ibat_min;
+ uint8_t val;
+ uint8_t val2;
+ uint8_t val_temp;
+
+
+ //get ocv table
+ for (i = 0; i <= 10; i = i+1) {
+ info->soca->ocv_table_def[i] = get_OCV_voltage(info, i, USING);
+ printk(KERN_INFO "PMU: %s : %d0%% voltage = %d uV\n",
+ __func__, i, info->soca->ocv_table_def[i]);
+ }
+
+ //save original header file data
+ for (i = 0; i < 32; i++){
+ info->soca->battery_init_para_original[i] = battery_init_para[info->num][i];
+ }
+
+ temp = (battery_init_para[info->num][24]<<8) | (battery_init_para[info->num][25]);
+ Rbat = temp * 1000 / 512 * 5000 / 4095;
+ info->soca->Rsys = Rbat + 55;
+
+ if ((info->fg_target_ibat == 0) || (info->fg_target_vsys == 0)) { /* normal version */
+
+ temp = (battery_init_para[info->num][22]<<8) | (battery_init_para[info->num][23]);
+ //fa_cap = get_check_fuel_gauge_reg(info, FA_CAP_H_REG, FA_CAP_L_REG,
+ // 0x7fff);
+
+ info->soca->target_ibat = temp*2/10; /* calc 0.2C*/
+ temp1 = (battery_init_para[info->num][0]<<8) | (battery_init_para[info->num][1]);
+// temp = get_OCV_voltage(info, 0) / 1000; /* unit is 1mv*/
+// info->soca->cutoff_ocv = info->soca->target_vsys - Ibat_min * info->soca->Rsys / 1000;
+
+ info->soca->target_vsys = temp1 + ( info->soca->target_ibat * info->soca->Rsys ) / 1000;
+
+
+ } else {
+ info->soca->target_ibat = info->fg_target_ibat;
+ /* calc min vsys value */
+ temp1 = (battery_init_para[info->num][0]<<8) | (battery_init_para[info->num][1]);
+ temp = temp1 + ( info->soca->target_ibat * info->soca->Rsys ) / 1000;
+ if( temp < info->fg_target_vsys) {
+ info->soca->target_vsys = info->fg_target_vsys;
+ } else {
+ info->soca->target_vsys = temp;
+ printk("PMU : %s : setting value of target vsys(%d) is out of range(%d)\n",__func__, info->fg_target_vsys, temp);
+ }
+ }
+
+ //for debug
+ printk("PMU : %s : target_vsys is %d target_ibat is %d\n",__func__,info->soca->target_vsys,info->soca->target_ibat);
+
+ if ((info->soca->target_ibat == 0) || (info->soca->target_vsys == 0)) { /* normal version */
+ } else { /*Slice cutoff voltage version. */
+
+ Ibat_min = -1 * info->soca->target_ibat;
+ info->soca->cutoff_ocv = info->soca->target_vsys - Ibat_min * info->soca->Rsys / 1000;
+
+ full_ocv = (battery_init_para[info->num][20]<<8) | (battery_init_para[info->num][21]);
+ full_ocv = full_ocv * 5000 / 4095;
+
+ ricoh61x_scaling_OCV_table(info, info->soca->cutoff_ocv, full_ocv, &start_per, &end_per);
+
+ /* calc available capacity */
+ /* get avilable capacity */
+ /* battery_init_para23-24 is designe capacity */
+ available_cap = (battery_init_para[info->num][22]<<8)
+ | (battery_init_para[info->num][23]);
+
+ available_cap = available_cap
+ * ((10000 - start_per) / 100) / 100 ;
+
+
+ battery_init_para[info->num][23] = available_cap;
+ battery_init_para[info->num][22] = available_cap >> 8;
+
+ }
+ ret = ricoh61x_clr_bits(info->dev->parent, FG_CTRL_REG, 0x01);
+ if (ret < 0) {
+ dev_err(info->dev, "error in FG_En off\n");
+ goto err;
+ }
+ /////////////////////////////////
+ ret = ricoh61x_read_bank1(info->dev->parent, 0xDC, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ val_temp = val;
+ val &= 0x0F; //clear bit 4-7
+ val |= 0x10; //set bit 4
+
+ ret = ricoh61x_write_bank1(info->dev->parent, 0xDC, val);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ ret = ricoh61x_read_bank1(info->dev->parent, 0xDC, &val2);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ ret = ricoh61x_write_bank1(info->dev->parent, 0xDC, val_temp);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ //printk("PMU : %s : original 0x%x, before 0x%x, after 0x%x\n",__func__, val_temp, val, val2);
+
+ if (val != val2) {
+ ret = ricoh61x_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 30, battery_init_para[info->num]);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+ } else {
+ ret = ricoh61x_read_bank1(info->dev->parent, 0xD2, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ ret = ricoh61x_read_bank1(info->dev->parent, 0xD3, &val2);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+
+ available_cap_ori = val2 + (val << 8);
+ available_cap = battery_init_para[info->num][23]
+ + (battery_init_para[info->num][22] << 8);
+
+ if (available_cap_ori == available_cap) {
+ ret = ricoh61x_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 22, battery_init_para[info->num]);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return ret;
+ }
+
+ for (i = 0; i < 6; i++) {
+ ret = ricoh61x_write_bank1(info->dev->parent, 0xD4+i, battery_init_para[info->num][24+i]);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return ret;
+ }
+ }
+ } else {
+ ret = ricoh61x_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 30, battery_init_para[info->num]);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ goto err;
+ }
+ }
+ }
+
+ ////////////////////////////////
+
+ return 0;
+err:
+ return ret;
+}
+
+/* Initial setting of battery */
+static int ricoh61x_init_battery(struct ricoh61x_battery_info *info)
+{
+ int ret = 0;
+ uint8_t val;
+ uint8_t val2;
+ unsigned long hour_power_off;
+ unsigned long hour_power_on;
+ long power_off_period;
+ unsigned long seconds;
+ int cc_cap = 0;
+ long cc_cap_mas = 0;
+ bool is_charging = true;
+
+ /* Need to implement initial setting of batery and error */
+ /* -------------------------- */
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+
+ /* set relaxation state */
+ if (RICOH61x_REL1_SEL_VALUE > 240)
+ val = 0x0F;
+ else
+ val = RICOH61x_REL1_SEL_VALUE / 16 ;
+
+ /* set relaxation state */
+ if (RICOH61x_REL2_SEL_VALUE > 120)
+ val2 = 0x0F;
+ else
+ val2 = RICOH61x_REL2_SEL_VALUE / 8 ;
+
+ val = val + (val2 << 4);
+
+ //ret = ricoh61x_write_bank1(info->dev->parent, BAT_REL_SEL_REG, val);
+ ret = ricoh61x_write_bank1(info->dev->parent, BAT_REL_SEL_REG, 0);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing BAT_REL_SEL_REG\n");
+ return ret;
+ }
+
+ ret = ricoh61x_read_bank1(info->dev->parent, BAT_REL_SEL_REG, &val);
+ //printk("PMU: ------- BAT_REL_SEL= %xh: =======\n",
+ // val);
+
+ ret = ricoh61x_write_bank1(info->dev->parent, BAT_TA_SEL_REG, 0x00);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing BAT_TA_SEL_REG\n");
+ return ret;
+ }
+
+ //check first power on condition
+ //initial value
+ info->first_pwon = 0;
+ ret = ricoh61x_read(info->dev->parent, PSWR_REG, &val);
+ if (ret < 0) {
+ dev_err(info->dev,"Error in reading PSWR_REG %d\n", ret);
+ return ret;
+ }
+
+ g_soc = val & 0x7f;
+ info->soca->init_pswr = val & 0x7f;
+ printk("PMU FG_RESET : %s : initial pswr = %d\n",__func__,info->soca->init_pswr);
+
+ if(val == 0){
+ printk("PMU : %s : first attached battery\n", __func__);
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 1);
+ info->first_pwon = 1;
+ }
+
+ //info->first_pwon = (val == 0) ? 1 : 0;
+
+ ret = ricoh61x_read(info->dev->parent, RICOH61x_PWR_OFF_HIS, &val);
+ if (ret < 0) {
+ dev_err(info->dev,"Error in reading PWER OFF HIS %d\n", ret);
+ return ret;
+ }
+ printk("PMU : %s : POWER off history 0x%02x is 0x%02x \n", __func__,RICOH61x_PWR_OFF_HIS ,val);
+ //check bit 0 status
+ if(val & 0x01){
+ printk("PMU : %s : Long power on key press\n", __func__);
+ info->first_pwon = 1;
+ }
+
+ ret = ricoh61x_read(info->dev->parent, RICOH61x_PWR_FUNC, &val);
+ if (ret < 0) {
+ dev_err(info->dev,"Error in reading PWER FUNC %d\n", ret);
+ return ret;
+ }
+ printk("PMU : %s : POWER control function 0x%02x is 0x%02x \n", __func__,RICOH61x_PWR_FUNC ,val);
+#if 0
+ //check all bit is clear or not
+ if((val & 0xFF) == 0){
+ printk("PMU : %s : cold boot\n", __func__);
+ info->first_pwon = 1;
+ }
+#endif
+ //end first power on condition
+
+ if(info->first_pwon == 0){
+ //check Power off period
+ //if upper 1day, this power on sequence become first power on
+ hour_power_off = get_storedTime_from_register(info);
+ get_current_time(info, &seconds);
+ hour_power_on = seconds / 3600;
+
+ hour_power_on &= 0xFFFFFF;
+
+ power_off_period = hour_power_on - hour_power_off;
+ if(power_off_period >= 24) {
+ bat_alert_req_flg = 1;
+ } else if(power_off_period < 0){
+ //error case
+ bat_alert_req_flg = 1;
+ } else {
+ bat_alert_req_flg = 0;
+ }
+ printk("PMU : %s : off is %lu, on is %lu, period is %lu, fpon_flag is %d\n", __func__, hour_power_off, hour_power_on, power_off_period, info->first_pwon);
+ }
+
+ if(info->first_pwon) {
+ info->soca->rsoc_ready_flag = 1;
+ }else {
+ info->soca->rsoc_ready_flag = 0;
+ }
+
+ ret = ricoh61x_set_OCV_table(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the OCV Tabler\n");
+ return ret;
+ }
+
+ ret = ricoh61x_write(info->dev->parent, FG_CTRL_REG, 0x11);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+
+
+ Enable_Test_Register(info);
+
+#endif
+
+#if 0
+ ret = ricoh61x_write(info->dev->parent, VINDAC_REG, 0x01);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+#endif
+
+#if 0
+ 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;
+ }
+#endif
+
+ return ret;
+}
+
+/* Initial setting of charger */
+static int ricoh61x_init_charger(struct ricoh61x_battery_info *info)
+{
+ int err;
+ uint8_t val;
+ uint8_t val2;
+ uint8_t val3;
+ int charge_status;
+ int vfchg_val;
+ int icchg_val;
+ int rbat;
+ int temp;
+
+ info->chg_ctr = 0;
+ info->chg_stat1 = 0;
+
+ err = ricoh61x_set_bits(info->dev->parent, RICOH61x_PWR_FUNC, 0x20);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the PWR FUNC register\n");
+ goto free_device;
+ }
+
+ charge_status = get_power_supply_status(info);
+
+ if (charge_status != POWER_SUPPLY_STATUS_FULL)
+ {
+ /* Disable charging */
+ err = ricoh61x_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;
+ }
+ }
+
+
+ err = ricoh61x_read(info->dev->parent, 0xDA, &val);
+ printk("PMU : %s : GCHGDET (0xDA) is 0x%x\n",__func__,val);
+ if (val & 0x30) {
+ /* REGISET1:(0xB6) setting */
+ if ((info->ch_ilim_adp != 0xFF) || (info->ch_ilim_adp <= 0x1D)) {
+ val = info->ch_ilim_adp;
+
+ }
+ else
+ val = 0x0D;
+ err = ricoh61x_write(info->dev->parent, REGISET1_REG,val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing REGISET1_REG %d\n",
+ err);
+ goto free_device;
+ }
+ }
+
+ /* REGISET2:(0xB7) setting */
+ err = ricoh61x_read(info->dev->parent, REGISET2_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read REGISET2_REG %d\n", err);
+ goto free_device;
+ }
+
+ if ((info->ch_ilim_usb != 0xFF) || (info->ch_ilim_usb <= 0x1D)) {
+ val2 = info->ch_ilim_usb;
+ } else {/* Keep OTP value */
+ val2 = (val & 0x1F);
+ }
+
+ /* keep bit 5-7 */
+ val &= 0xE0;
+
+ val = val + val2;
+
+ val |= 0xA0; // Set SDPOVRLIM to allow charge limit 500mA
+
+ err = ricoh61x_write(info->dev->parent, REGISET2_REG,val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing REGISET2_REG %d\n",
+ err);
+ goto free_device;
+ }
+
+ err = ricoh61x_read(info->dev->parent, CHGISET_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read CHGISET_REG %d\n", err);
+ goto free_device;
+ }
+
+ /* Define Current settings value for charging (bit 4~0)*/
+ if ((info->ch_ichg != 0xFF) || (info->ch_ichg <= 0x1D)) {
+ val2 = info->ch_ichg;
+ } else { /* Keep OTP value */
+ val2 = (val & 0x1F);
+ }
+
+ /* Define Current settings at the charge completion (bit 7~6)*/
+ if ((info->ch_icchg != 0xFF) || (info->ch_icchg <= 0x03)) {
+ val3 = info->ch_icchg << 6;
+ } else { /* Keep OTP value */
+ val3 = (val & 0xC0);
+ }
+
+ val = val2 + val3;
+
+ err = ricoh61x_write(info->dev->parent, CHGISET_REG, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing CHGISET_REG %d\n",
+ err);
+ goto free_device;
+ }
+
+ //debug messeage
+ err = ricoh61x_read(info->dev->parent, CHGISET_REG,&val);
+ printk("PMU : %s : after CHGISET_REG (0x%x) is 0x%x info->ch_ichg is 0x%x info->ch_icchg is 0x%x\n",__func__,CHGISET_REG,val,info->ch_ichg,info->ch_icchg);
+
+ //debug messeage
+ err = ricoh61x_read(info->dev->parent, BATSET1_REG,&val);
+ printk("PMU : %s : before BATSET1_REG (0x%x) is 0x%x info->ch_vbatovset is 0x%x\n",__func__,BATSET1_REG,val,info->ch_vbatovset);
+
+ /* BATSET1_REG(0xBA) setting */
+ err = ricoh61x_read(info->dev->parent, BATSET1_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read BATSET1 register %d\n", err);
+ goto free_device;
+ }
+
+ /* Define Battery overvoltage (bit 4)*/
+ if ((info->ch_vbatovset != 0xFF) || (info->ch_vbatovset <= 0x1)) {
+ val2 = info->ch_vbatovset;
+ val2 = val2 << 4;
+ } else { /* Keep OTP value */
+ val2 = (val & 0x10);
+ }
+
+ /* keep bit 0-3 and bit 5-7 */
+ val = (val & 0xEF);
+
+ val = val + val2;
+
+ val |= 0x08; // set vweak to 3.3
+
+ err = ricoh61x_write(info->dev->parent, BATSET1_REG, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing BAT1_REG %d\n",
+ err);
+ goto free_device;
+ }
+ //debug messeage
+ err = ricoh61x_read(info->dev->parent, BATSET1_REG,&val);
+ printk("PMU : %s : after BATSET1_REG (0x%x) is 0x%x info->ch_vbatovset is 0x%x\n",__func__,BATSET1_REG,val,info->ch_vbatovset);
+
+ //debug messeage
+ err = ricoh61x_read(info->dev->parent, BATSET2_REG,&val);
+ printk("PMU : %s : before BATSET2_REG (0x%x) is 0x%x info->ch_vrchg is 0x%x info->ch_vfchg is 0x%x \n",__func__,BATSET2_REG,val,info->ch_vrchg,info->ch_vfchg);
+
+
+ /* BATSET2_REG(0xBB) setting */
+ err = ricoh61x_read(info->dev->parent, BATSET2_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read BATSET2 register %d\n", err);
+ goto free_device;
+ }
+
+ /* Define Re-charging voltage (bit 2~0)*/
+ if ((info->ch_vrchg != 0xFF) || (info->ch_vrchg <= 0x04)) {
+ val2 = info->ch_vrchg;
+ } else { /* Keep OTP value */
+ val2 = (val & 0x07);
+ }
+
+ /* Define FULL charging voltage (bit 6~4)*/
+ if ((info->ch_vfchg != 0xFF) || (info->ch_vfchg <= 0x04)) {
+ val3 = info->ch_vfchg;
+ val3 = val3 << 4;
+ } else { /* Keep OTP value */
+ val3 = (val & 0x70);
+ }
+
+ /* keep bit 3 and bit 7 */
+ val = (val & 0x88);
+
+ val = val + val2 + val3;
+
+ err = ricoh61x_write(info->dev->parent, BATSET2_REG, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing RICOH61x_RE_CHARGE_VOLTAGE %d\n",
+ err);
+ 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 = ricoh61x_read(info->dev->parent, RICOH61x_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 = ricoh61x_write(info->dev->parent, RICOH61x_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 = ricoh61x_write(info->dev->parent, RICOH61x_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 = ricoh61x_read(info->dev->parent, RICOH61x_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 = ricoh61x_write(info->dev->parent, RICOH61x_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 = ricoh61x_write(info->dev->parent, RICOH61x_INT_MSK_CHGCTR, 0xfc);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+ err);
+ goto free_device;
+ }
+
+ if (charge_status != POWER_SUPPLY_STATUS_FULL)
+ {
+ /* Enable charging */
+ err = ricoh61x_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;
+ }
+ }
+ /* get OCV100_min, OCV100_min*/
+ temp = (battery_init_para[info->num][24]<<8) | (battery_init_para[info->num][25]);
+ rbat = temp * 1000 / 512 * 5000 / 4095;
+
+ /* get vfchg value */
+ err = ricoh61x_read(info->dev->parent, BATSET2_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in reading the batset2reg\n");
+ goto free_device;
+ }
+ val &= 0x70;
+ val2 = val >> 4;
+ if (val2 <= 3) {
+ vfchg_val = 4050 + val2 * 50;
+ } else {
+ vfchg_val = 4350;
+ }
+ printk("PMU : %s : test test val %d, val2 %d vfchg %d\n", __func__, val, val2, vfchg_val);
+
+ /* get value */
+ err = ricoh61x_read(info->dev->parent, CHGISET_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in reading the chgisetreg\n");
+ goto free_device;
+ }
+ val &= 0xC0;
+ val2 = val >> 6;
+ icchg_val = 50 + val2 * 50;
+ printk("PMU : %s : test test val %d, val2 %d icchg %d\n", __func__, val, val2, icchg_val);
+
+ info->soca->OCV100_min = ( vfchg_val * 99 / 100 - (icchg_val * (rbat +20))/1000 - 20 ) * 1000;
+ info->soca->OCV100_max = ( vfchg_val * 101 / 100 - (icchg_val * (rbat +20))/1000 + 20 ) * 1000;
+
+ printk("PMU : %s : 100 min %d, 100 max %d vfchg %d icchg %d rbat %d\n",__func__,
+ info->soca->OCV100_min,info->soca->OCV100_max,vfchg_val,icchg_val,rbat);
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ /* Set ADRQ=00 to stop ADC */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_CNT3, 0x0);
+#if 0
+ /* Enable VSYS threshold Low interrupt */
+ ricoh61x_write(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x10);
+ /* Set ADC auto conversion interval 250ms */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_CNT2, 0x0);
+ /* Enable VSYS pin conversion in auto-ADC */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_CNT1, 0x10);
+ /* Set VSYS threshold low voltage value = (voltage(V)*255)/(3*2.5) */
+ val = info->alarm_vol_mv * 255 / 7500;
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VSYS_THL, val);
+#else
+ /* Enable VBAT threshold Low interrupt */
+ ricoh61x_write(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x02);
+ /* Set ADC auto conversion interval 250ms */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_CNT2, 0x0);
+ /* Enable VBAT pin conversion in auto-ADC */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_CNT1, 0x12);
+ /* Set VBAT threshold low voltage value = (voltage(V)*255)/(2*2.5) */
+ val = (info->alarm_vol_mv - 20) * 255 / 5000;
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VBAT_THL, val);
+#endif
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+ /* Enable VTHM threshold Low interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_ADC_CNT1, 0x20);
+ /* Enable VBAT threshold Low interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x20);
+ /* Set VTHM threshold low voltage value = (voltage(V)*255)/(2.5) */
+ val = HIGH_BATTERY_TEMP_VOL * 255 / 2500;
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VTHM_THL, val);
+ /* Enable VTHM threshold high interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC2, 0x20);
+ /* Set VTHM threshold high voltage value = (voltage(V)*255)/(2.5) */
+ val = LOW_BATTERY_TEMP_VOL * 255 / 2500;
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VTHM_THH, val);
+#endif
+
+ /* Start auto-mode & average 4-time conversion mode for ADC */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_CNT3, 0x28);
+
+#endif
+
+free_device:
+ return err;
+}
+
+
+static int get_power_supply_status(struct ricoh61x_battery_info *info)
+{
+ uint8_t status;
+ uint8_t supply_state;
+ uint8_t charge_state;
+ int ret = 0;
+
+ /* get power supply status */
+ ret = ricoh61x_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 (info->entry_factory_mode)
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+ 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 int get_power_supply_Android_status(struct ricoh61x_battery_info *info)
+{
+
+ get_power_supply_status(info);
+
+ /* get power supply status */
+ if (info->entry_factory_mode)
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+ switch (info->soca->chg_status) {
+ case POWER_SUPPLY_STATUS_UNKNOWN:
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+
+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+
+ case POWER_SUPPLY_STATUS_DISCHARGING:
+ return POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+
+ case POWER_SUPPLY_STATUS_CHARGING:
+ return POWER_SUPPLY_STATUS_CHARGING;
+ break;
+
+ case POWER_SUPPLY_STATUS_FULL:
+ if(info->soca->displayed_soc == 100 * 100) {
+ return POWER_SUPPLY_STATUS_FULL;
+ } else {
+ return POWER_SUPPLY_STATUS_CHARGING;
+ }
+ break;
+ default:
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ }
+
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+extern int ricoh619_charger_detect(void);
+typedef void (*usb_insert_handler) (char inserted);
+extern usb_insert_handler mxc_misc_report_usb;
+
+static int giRICOH619_DCIN;
+int ricoh619_dcin_status(void)
+{
+ return giRICOH619_DCIN;
+}
+
+static void charger_irq_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info
+ = container_of(work, struct ricoh61x_battery_info, irq_work);
+ //uint8_t status;
+ int ret = 0;
+ uint8_t val = 0, ilim_adp = 0, ichg = 0;
+ //uint8_t adp_current_val = 0x0E;
+ //uint8_t usb_current_val = 0x04;
+ extern void led_red(int isOn);
+
+ printk(KERN_INFO "PMU:%s In\n", __func__);
+
+ power_supply_changed(&info->battery);
+
+#if defined (STANDBY_MODE_DEBUG)
+ ret = ricoh61x_read(info->dev->parent, CHGSTATE_REG, &val);
+ if (val & 0xc0) {
+ if(multiple_sleep_mode == 0) {
+ multiple_sleep_mode = 1;
+ printk("PMU: %s sleep time ratio = x60 *****************\n", __func__);
+ } else if(multiple_sleep_mode == 1) {
+ multiple_sleep_mode = 2;
+ printk("PMU: %s sleep time ratio = x3600 *****************\n", __func__);
+ } else if(multiple_sleep_mode == 2) {
+ multiple_sleep_mode = 0;
+ printk("PMU: %s sleep time ratio = x1 *****************\n", __func__);
+ }
+ }
+#elif defined(CHANGE_FL_MODE_DEBUG)
+ ret = ricoh61x_read(info->dev->parent, CHGSTATE_REG, &val);
+ if (val & 0xc0) {
+ if (fl_current < 10000) {
+ fl_current = 10000; // If FL<10mA, Set FL=10mA
+ } else if (fl_current < 20000) {
+ fl_current = 20000; // If FL<20mA, Set FL=20mA
+ } else if (fl_current < 30000) {
+ fl_current = 30000; // If FL<30mA, Set FL=30mA
+ } else if (fl_current < 40000) {
+ fl_current = 40000; // If FL<40mA, Set FL=40mA
+ } else {
+ fl_current = 5000; // If FL>40mA, Set FL=5mA
+ }
+ printk("PMU: %s FL(%d) mA *****************\n", __func__, fl_current/1000);
+ }
+#endif
+// mutex_lock(&info->lock);
+
+#if 0
+ if(info->chg_ctr & 0x02) {
+ uint8_t sts;
+ ret = ricoh61x_read(info->dev->parent, RICOH61x_INT_MON_CHGCTR, &sts);
+ if (ret < 0)
+ dev_err(info->dev, "Error in reading the control register\n");
+
+ sts &= 0x02;
+
+ /* If "sts" is true, USB is plugged. If not, unplugged. */
+ }
+#endif
+ info->chg_ctr = 0;
+ info->chg_stat1 = 0;
+
+ /* Enable Interrupt for VADP/VUSB */
+ ret = ricoh61x_write(info->dev->parent, RICOH61x_INT_MSK_CHGCTR, 0xfc);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable charger mask INT %d\n",
+ __func__, ret);
+
+ /* Enable Interrupt for Charging & complete */
+ ret = ricoh61x_write(info->dev->parent, RICOH61x_INT_MSK_CHGSTS1, 0xfc);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable charger mask INT %d\n",
+ __func__, ret);
+
+ /* set USB/ADP ILIM */
+ ret = ricoh61x_read(info->dev->parent, CHGSTATE_REG, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return;
+ }
+
+ val = (val & 0xC0) >> 6;
+ switch (val) {
+ case 0: // plug out USB/ADP
+ printk("%s : val = %d plug out\n",__func__, val);
+ break;
+ case 1: // plug in ADP
+ printk("%s : val = %d plug in ADPt\n",__func__, val);
+ //Add the code of AC adapter Charge and Limit current settings
+ //ret = ricoh61x_write(info->dev->parent, REGISET1_REG, adp_current_val);
+ break;
+ case 2:// plug in USB
+ printk("%s : val = %d plug in USB\n",__func__, val);
+ //Add the code of USB Charge and Limit current settings
+ //ret = ricoh61x_write(info->dev->parent, REGISET2_REG, usb_current_val)
+ break;
+ case 3:// plug in USB/ADP
+ printk("%s : val = %d plug in ADP USB\n",__func__, val);
+ break;
+ default:
+ printk("%s : val = %d unknown\n",__func__, val);
+ break;
+ }
+
+
+ giRICOH619_DCIN = ricoh619_charger_detect();
+ if(giRICOH619_DCIN) {
+ led_red(1);
+ }
+ else {
+ led_red(0);
+ }
+
+ //ricoh61x_read(info->dev->parent, 0xDA, &status);
+ ricoh61x_read(info->dev->parent, CHGISET_REG, &val);
+ val &= 0xe0;
+ //if (status&0x30)
+ if(giRICOH619_DCIN==CDP_CHARGER||giRICOH619_DCIN==DCP_CHARGER)
+ { // set 1000mA if DCP(10) or CDP(01) .
+ switch (gptHWCFG->m_val.bPCB) {
+ case 49: //E60QDX
+ ilim_adp = 0x09; //1000mA
+ ichg = 0x07; //800mA
+ break;
+ default:
+ ilim_adp = 0x0D; //1400mA
+ ichg = 0x09; //1000mA
+ break;
+ }
+ ricoh61x_write(info->dev->parent, REGISET1_REG, ilim_adp);
+ ricoh61x_write(info->dev->parent, CHGISET_REG, val|ichg);
+ }
+ else
+ {
+ ricoh61x_write(info->dev->parent, REGISET1_REG, 0x04);
+ ricoh61x_write(info->dev->parent, CHGISET_REG, val|0x04);
+ }
+ if(mxc_misc_report_usb) {
+ mxc_misc_report_usb(giRICOH619_DCIN?1:0);
+ }
+
+// mutex_unlock(&info->lock);
+ printk(KERN_INFO "PMU:%s Out\n", __func__);
+}
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+static void low_battery_irq_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, low_battery_work.work);
+
+ int ret = 0;
+
+ printk(KERN_INFO "PMU:%s In\n", __func__);
+
+ critical_low_flag = 1;
+ power_supply_changed(&info->battery);
+ info->suspend_state = false;
+ printk(KERN_INFO "PMU:%s Set ciritical_low_flag = 1 **********\n", __func__);
+
+#if 0
+ /* Enable VSYS threshold Low interrupt */
+ ricoh61x_write(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x10);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable adc mask INT %d\n",
+ __func__, ret);
+#endif
+}
+#endif
+
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+static void battery_temp_irq_work(struct work_struct *work)
+{
+ struct ricoh61x_battery_info *info = container_of(work,
+ struct ricoh61x_battery_info, battery_temp_work.work);
+
+ int ret = 0;
+ uint8_t val;
+ uint8_t high_temp_vol = HIGH_BATTERY_TEMP_VOL*255/2500;
+ uint8_t low_temp_vol = LOW_BATTERY_TEMP_VOL*255/2500;
+
+ printk(KERN_INFO "PMU:%s In\n", __func__);
+
+ power_supply_changed(&info->battery);
+
+ ricoh61x_read(info->dev->parent, RICOH61x_ADC_VTHMDATAH, &val);
+ printk(KERN_INFO "PMU:%s Battery temperature triggered (VTHMDATA 0x%02X)**********\n", __func__, val);
+
+ if (val < high_temp_vol) {
+ /* Set VTHM threshold high voltage value = (voltage(V)*255)/(2.5) */
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VTHM_THH, high_temp_vol);
+ printk(KERN_INFO "PMU:%s set VTHM_THH to %02X\n", __func__, high_temp_vol);
+ /* Enable VTHM threshold high interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC2, 0x20);
+ }
+ else if (val > low_temp_vol) {
+ /* Set VTHM threshold low voltage value = (voltage(V)*255)/(2.5) */
+ printk(KERN_INFO "PMU:%s set VTHM_THL to %02X\n", __func__, low_temp_vol);
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VTHM_THL, low_temp_vol);
+ /* Enable VBAT threshold Low interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x20);
+ }
+ else {
+ /* Set VTHM threshold low voltage value = (voltage(V)*255)/(2.5) */
+ val = HIGH_BATTERY_TEMP_VOL * 255 / 2500;
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VTHM_THL, val);
+ printk(KERN_INFO "PMU:%s set VTHM_THL to %02X\n", __func__, val);
+ /* Enable VBAT threshold Low interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x20);
+ /* Set VTHM threshold high voltage value = (voltage(V)*255)/(2.5) */
+ val = LOW_BATTERY_TEMP_VOL * 255 / 2500;
+ ricoh61x_write(info->dev->parent, RICOH61x_ADC_VTHM_THH, val);
+ printk(KERN_INFO "PMU:%s set VTHM_THH to %02X\n", __func__, val);
+ /* Enable VTHM threshold high interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC2, 0x20);
+ }
+}
+#endif
+
+static irqreturn_t charger_in_isr(int irq, void *battery_info)
+{
+ struct ricoh61x_battery_info *info = battery_info;
+ printk(KERN_INFO "PMU:%s\n", __func__);
+
+ info->chg_stat1 |= 0x01;
+ queue_work(info->workqueue, &info->irq_work);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_complete_isr(int irq, void *battery_info)
+{
+ struct ricoh61x_battery_info *info = battery_info;
+ printk(KERN_INFO "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 ricoh61x_battery_info *info = battery_info;
+ printk(KERN_INFO "PMU:%s\n", __func__);
+
+ info->chg_ctr |= 0x02;
+
+ queue_work(info->workqueue, &info->irq_work);
+
+ info->soca->dischg_state = 0;
+ info->soca->chg_count = 0;
+ if (RICOH61x_SOCA_UNSTABLE == info->soca->status
+ || RICOH61x_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 ricoh61x_battery_info *info = battery_info;
+ printk(KERN_INFO "PMU:%s\n", __func__);
+
+ info->chg_ctr |= 0x01;
+ queue_work(info->workqueue, &info->irq_work);
+
+ info->soca->dischg_state = 0;
+ info->soca->chg_count = 0;
+ if (RICOH61x_SOCA_UNSTABLE == info->soca->status
+ || RICOH61x_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 ricoh61x_battery_info *info = battery_info;
+
+ printk(KERN_INFO "PMU:%s\n", __func__);
+ printk(KERN_INFO "PMU:%s Detect Low Battery Interrupt **********\n", __func__);
+ // critical_low_flag = 1;
+ queue_delayed_work(info->monitor_wqueue, &info->low_battery_work,
+ LOW_BATTERY_DETECTION_TIME*HZ);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+/*************************************************************/
+/* for Detecting Battery Temperature */
+/*************************************************************/
+
+static irqreturn_t adc_vtherm_isr(int irq, void *battery_info)
+{
+
+ struct ricoh61x_battery_info *info = battery_info;
+
+ printk(KERN_INFO "PMU:%s\n", __func__);
+ printk(KERN_INFO "PMU:%s Detect Battery Temperature Interrupt **********\n", __func__);
+ queue_delayed_work(info->monitor_wqueue, &info->battery_temp_work, 0);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * Get Charger Priority
+ * - get higher-priority between VADP and VUSB
+ * @ data: higher-priority is stored
+ * true : VUSB
+ * false: VADP
+ */
+static int get_charge_priority(struct ricoh61x_battery_info *info, bool *data)
+{
+ int ret = 0;
+ uint8_t val = 0;
+
+ ret = ricoh61x_read(info->dev->parent, CHGCTL1_REG, &val);
+ val = val >> 7;
+ *data = (bool)val;
+
+ return ret;
+}
+
+/*
+ * Set Charger Priority
+ * - set higher-priority between VADP and VUSB
+ * - data: higher-priority is stored
+ * true : VUSB
+ * false: VADP
+ */
+static int set_charge_priority(struct ricoh61x_battery_info *info, bool *data)
+{
+ int ret = 0;
+ uint8_t val = 0x80;
+
+ if (*data == 1)
+ ret = ricoh61x_set_bits(info->dev->parent, CHGCTL1_REG, val);
+ else
+ ret = ricoh61x_clr_bits(info->dev->parent, CHGCTL1_REG, val);
+
+ return ret;
+}
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+static int get_check_fuel_gauge_reg(struct ricoh61x_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 = ricoh61x_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 = ricoh61x_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 ricoh61x_battery_info *info)
+{
+ uint8_t capacity;
+ long capacity_l;
+ int temp;
+ int ret = 0;
+ int nt;
+ int temperature;
+ int cc_cap = 0;
+ long cc_cap_mas =0;
+ int cc_delta;
+ bool is_charging = true;
+
+ if (info->soca->rsoc_ready_flag != 0) {
+ /* get remaining battery capacity from fuel gauge */
+ ret = ricoh61x_read(info->dev->parent, SOC_REG, &capacity);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+ capacity_l = (long)capacity;
+ } else {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 0);
+ cc_delta = (is_charging == true) ? cc_cap : -cc_cap;
+ capacity_l = (info->soca->init_pswr * 100 + cc_delta) / 100;
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU FG_RESET : %s : capacity %d init_pswr %d cc_delta %d\n",__func__, capacity_l, info->soca->init_pswr, cc_delta);
+#endif
+ }
+
+ temperature = get_battery_temp_2(info) / 10; /* unit 0.1 degree -> 1 degree */
+
+ if (temperature >= 25) {
+ nt = 0;
+ } else if (temperature >= 5) {
+ nt = (25 - temperature) * RICOH61x_TAH_SEL2 * 625 / 100;
+ } else {
+ nt = (625 + (5 - temperature) * RICOH61x_TAL_SEL2 * 625 / 100);
+ }
+
+ temp = capacity_l * 100 * 100 / (10000 - nt);
+
+ temp = min(100, temp);
+ temp = max(0, temp);
+
+ return temp; /* Unit is 1% */
+}
+
+static int calc_capacity_2(struct ricoh61x_battery_info *info)
+{
+ uint8_t val;
+ long capacity;
+ int re_cap, fa_cap;
+ int temp;
+ int ret = 0;
+ int nt;
+ int temperature;
+ int cc_cap = 0;
+ long cc_cap_mas =0;
+ int cc_delta;
+ bool is_charging = true;
+
+
+ if (info->soca->rsoc_ready_flag != 0) {
+ re_cap = get_check_fuel_gauge_reg(info, RE_CAP_H_REG, RE_CAP_L_REG,
+ 0x7fff);
+ fa_cap = get_check_fuel_gauge_reg(info, FA_CAP_H_REG, FA_CAP_L_REG,
+ 0x7fff);
+
+ if (fa_cap != 0) {
+ capacity = ((long)re_cap * 100 * 100 / fa_cap);
+ capacity = (long)(min(10000, (int)capacity));
+ capacity = (long)(max(0, (int)capacity));
+ } else {
+ ret = ricoh61x_read(info->dev->parent, SOC_REG, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+ capacity = (long)val * 100;
+ }
+ } else {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas, &is_charging, 0);
+ cc_delta = (is_charging == true) ? cc_cap : -cc_cap;
+ capacity = info->soca->init_pswr * 100 + cc_delta;
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU FG_RESET : %s : capacity %d init_pswr %d cc_delta %d\n",__func__, (int)capacity, info->soca->init_pswr, cc_delta);
+#endif
+ }
+
+ temperature = get_battery_temp_2(info) / 10; /* unit 0.1 degree -> 1 degree */
+
+ if (temperature >= 25) {
+ nt = 0;
+ } else if (temperature >= 5) {
+ nt = (25 - temperature) * RICOH61x_TAH_SEL2 * 625 / 100;
+ } else {
+ nt = (625 + (5 - temperature) * RICOH61x_TAL_SEL2 * 625 / 100);
+ }
+
+ temp = (int)(capacity * 100 * 100 / (10000 - nt));
+
+ temp = min(10000, temp);
+ temp = max(0, temp);
+
+ return temp; /* Unit is 0.01% */
+}
+
+static int get_battery_temp(struct ricoh61x_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 = (~ret + 1) & 0x7ff;
+ ret = -1 * ret * 625 / 1000;
+ }
+
+ return ret;
+}
+
+static int get_battery_temp_2(struct ricoh61x_battery_info *info)
+{
+ uint8_t reg_buff[2];
+ long temp, temp_off, temp_gain;
+ bool temp_sign, temp_off_sign, temp_gain_sign;
+ int Vsns = 0;
+ int Iout = 0;
+ int Vthm, Rthm;
+ int reg_val = 0;
+ int new_temp;
+ long R_ln1, R_ln2;
+ int ret = 0;
+
+ /* Calculate TEMP */
+ 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 register\n");
+ goto out;
+ }
+
+ reg_val = ret;
+ temp_sign = (reg_val & 0x0800) >> 11;
+ reg_val = (reg_val & 0x07ff);
+
+ if (temp_sign == 0) /* positive value part */
+ /* the unit is 0.0001 degree */
+ temp = (long)reg_val * 625;
+ else { /*negative value part */
+ reg_val = (~reg_val + 1) & 0x7ff;
+ temp = -1 * (long)reg_val * 625;
+ }
+
+ /* Calculate TEMP_OFF */
+ ret = ricoh61x_bulk_reads_bank1(info->dev->parent,
+ TEMP_OFF_H_REG, 2, reg_buff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge register\n");
+ goto out;
+ }
+
+ reg_val = reg_buff[0] << 8 | reg_buff[1];
+ temp_off_sign = (reg_val & 0x0800) >> 11;
+ reg_val = (reg_val & 0x07ff);
+
+ if (temp_off_sign == 0) /* positive value part */
+ /* the unit is 0.0001 degree */
+ temp_off = (long)reg_val * 625;
+ else { /*negative value part */
+ reg_val = (~reg_val + 1) & 0x7ff;
+ temp_off = -1 * (long)reg_val * 625;
+ }
+
+ /* Calculate TEMP_GAIN */
+ ret = ricoh61x_bulk_reads_bank1(info->dev->parent,
+ TEMP_GAIN_H_REG, 2, reg_buff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge register\n");
+ goto out;
+ }
+
+ reg_val = reg_buff[0] << 8 | reg_buff[1];
+ temp_gain_sign = (reg_val & 0x0800) >> 11;
+ reg_val = (reg_val & 0x07ff);
+
+ if (temp_gain_sign == 0) /* positive value part */
+ /* 1 unit is 0.000488281. the result is 0.01 */
+ temp_gain = (long)reg_val * 488281 / 100000;
+ else { /*negative value part */
+ reg_val = (~reg_val + 1) & 0x7ff;
+ temp_gain = -1 * (long)reg_val * 488281 / 100000;
+ }
+
+ /* Calculate VTHM */
+ if (0 != temp_gain)
+ Vthm = (int)((temp - temp_off) / 4095 * 2500 / temp_gain);
+ else {
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU %s Skip to compensate temperature\n", __func__);
+#endif
+ goto out;
+ }
+
+ ret = measure_Ibatt_FG(info, &Iout);
+ Vsns = Iout * 2 / 100;
+
+ if (temp < -120000) {
+ /* Low Temperature */
+ if (0 != (2500 - Vthm)) {
+ Rthm = 10 * 10 * (Vthm - Vsns) / (2500 - Vthm);
+ } else {
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU %s Skip to compensate temperature\n", __func__);
+#endif
+ goto out;
+ }
+
+ R_ln1 = Rthm / 10;
+ R_ln2 = (R_ln1 * R_ln1 * R_ln1 * R_ln1 * R_ln1 / 100000
+ - R_ln1 * R_ln1 * R_ln1 * R_ln1 * 2 / 100
+ + R_ln1 * R_ln1 * R_ln1 * 11
+ - R_ln1 * R_ln1 * 2980
+ + R_ln1 * 449800
+ - 784000) / 10000;
+
+ /* the unit of new_temp is 0.1 degree */
+ new_temp = (int)((100 * 1000 * B_VALUE / (R_ln2 + B_VALUE * 100 * 1000 / 29815) - 27315) / 10);
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU %s low temperature %d\n", __func__, new_temp/10);
+#endif
+ } else if (temp > 520000) {
+ /* High Temperature */
+ if (0 != (2500 - Vthm)) {
+ Rthm = 100 * 10 * (Vthm - Vsns) / (2500 - Vthm);
+ } else {
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU %s Skip to compensate temperature\n", __func__);
+#endif
+ goto out;
+ }
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU %s [Rthm] Rthm %d[ohm]\n", __func__, Rthm);
+#endif
+
+ R_ln1 = Rthm / 10;
+ R_ln2 = (R_ln1 * R_ln1 * R_ln1 * R_ln1 * R_ln1 / 100000 * 15652 / 100
+ - R_ln1 * R_ln1 * R_ln1 * R_ln1 / 1000 * 23103 / 100
+ + R_ln1 * R_ln1 * R_ln1 * 1298 / 100
+ - R_ln1 * R_ln1 * 35089 / 100
+ + R_ln1 * 50334 / 10
+ - 48569) / 100;
+ /* the unit of new_temp is 0.1 degree */
+ new_temp = (int)((100 * 100 * B_VALUE / (R_ln2 + B_VALUE * 100 * 100 / 29815) - 27315) / 10);
+#ifdef _RICOH619_DEBUG_
+ printk(KERN_DEBUG"PMU %s high temperature %d\n", __func__, new_temp/10);
+#endif
+ } else {
+ /* the unit of new_temp is 0.1 degree */
+ new_temp = temp / 1000;
+ }
+
+ return new_temp;
+
+out:
+ new_temp = get_battery_temp(info);
+ return new_temp;
+}
+
+static int get_time_to_empty(struct ricoh61x_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 ricoh61x_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 ricoh61x_battery_info *info, int *data)
+{
+ int ret = 0;
+
+ if(info->soca->ready_fg == 1) {
+ 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;
+ info->soca->Vbat_old = *data;
+ } else {
+ *data = info->soca->Vbat_old;
+ }
+
+ return ret;
+}
+
+static int measure_Ibatt_FG(struct ricoh61x_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;
+}
+
+/**
+* index : index No.(2 -> 20%)
+* table_num : ocv table selection
+* 0 : Original Table(defined by header file)
+* 1 : Using Table
+*/
+static int get_OCV_init_Data(struct ricoh61x_battery_info *info, int index, int table_num)
+{
+ int ret = 0;
+ if (table_num == USING) {
+ ret = (battery_init_para[info->num][index*2]<<8) | (battery_init_para[info->num][index*2+1]);
+ } else if (table_num == ORIGINAL) {
+ ret = (info->soca->battery_init_para_original[index*2]<<8)
+ | (info->soca->battery_init_para_original[index*2+1]);
+ }
+ return ret;
+}
+
+/**
+* index : index No.(2 -> 20%)
+* table_num : ocv table selection
+* 0 : Original Table
+* 1 : Using Table
+*/
+static int get_OCV_voltage(struct ricoh61x_battery_info *info, int index, int table_num)
+{
+ int ret = 0;
+ ret = get_OCV_init_Data(info, index, table_num);
+ /* 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 ricoh61x_battery_info *info, int *data)
+{
+ int i;
+ uint8_t data_l = 0, data_h = 0;
+ int ret;
+
+ /* ADC interrupt enable */
+ ret = ricoh61x_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 = ricoh61x_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 = ricoh61x_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);
+ dev_info(info->dev, "ADC conversion times: %d\n", i);
+ /* read completed flag of ADC */
+ ret = ricoh61x_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 = ricoh61x_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 = ricoh61x_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 int measure_vsys_ADC(struct ricoh61x_battery_info *info, int *data)
+{
+ uint8_t data_l = 0, data_h = 0;
+ int ret;
+
+ ret = ricoh61x_read(info->dev->parent, VSYSDATAH_REG, &data_h);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ }
+
+ ret = ricoh61x_read(info->dev->parent, VSYSDATAL_REG, &data_l);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ }
+
+ *data = ((data_h & 0xff) << 4) | (data_l & 0x0f);
+ *data = *data * 1000 * 3 * 5 / 2 / 4095;
+ /* return unit should be 1uV */
+ *data = *data * 1000;
+
+ return 0;
+}
+
+static void ricoh61x_external_power_changed(struct power_supply *psy)
+{
+ struct ricoh61x_battery_info *info;
+
+ info = container_of(psy, struct ricoh61x_battery_info, battery);
+ queue_delayed_work(info->monitor_wqueue,
+ &info->changed_work, HZ / 2);
+ return;
+}
+
+static int gRicoh619_cur_voltage;
+
+int ricoh619_battery_2_msp430_adc(void)
+{
+ int i, battValue, result;
+ const unsigned short battGasgauge[] = {
+ // 3.0V, 3.1V, 3.2V, 3.3V, 3.4V, 3.5V, 3.6V, 3.7V, 3.8V, 3.9V, 4.0V, 4.1V, 4.2V,
+ 767, 791, 812, 833, 852, 877, 903, 928, 950, 979, 993, 1019, 1023,
+ };
+ if (critical_low_flag) return 0;
+
+ if ((!gRicoh619_cur_voltage) || (3000 > gRicoh619_cur_voltage) || (4200 < gRicoh619_cur_voltage))
+ return 1023;
+
+ i = (gRicoh619_cur_voltage - 3000)/100;
+ if (gRicoh619_cur_voltage % 100) {
+ result = (gRicoh619_cur_voltage % 100)/ (100 / (battGasgauge[i+1]-battGasgauge[i]));
+ result += battGasgauge[i];
+ }
+ else
+ result = battGasgauge[i];
+ return result;
+}
+
+static int ricoh61x_batt_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ricoh61x_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 = ricoh61x_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;
+ }
+ //printk("status : 0x%02x \n", status)
+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+ val->intval = (status & 0x80 ? 3 : 0);
+ else if (psy->type == POWER_SUPPLY_TYPE_USB)
+ val->intval = (status & 0x40 ? 3 : 0);
+ else
+ val->intval = (status & 0xC0 ? 3 : 0);
+ //yian, check charge full
+ if (val->intval == 3) {
+ uint8_t rd_status = (status & 0x1F);
+ //printk("rd_status : 0x%02x \n", rd_status);
+ if (rd_status == 0x04) //00100 Charge Complete
+ val->intval = 1;
+ }
+ break;
+ /* this setting is same as battery driver of 584 */
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = get_power_supply_Android_status(info);
+ if (POWER_SUPPLY_STATUS_FULL == ret)
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else
+ val->intval = ret;
+ info->status = ret;
+ dev_dbg(info->dev, "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 got 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;
+ data = info->cur_voltage * 1000;
+ }
+#else
+ ret = measure_vbatt_ADC(info, &data);
+#endif
+ val->intval = data;
+ /* convert unit uV -> mV */
+ info->cur_voltage = data / 1000;
+
+ gRicoh619_cur_voltage = info->cur_voltage;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev, "battery voltage is %d mV\n",
+ info->cur_voltage);
+#endif
+ break;
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+ /* current battery capacity is get from fuel gauge */
+ case POWER_SUPPLY_PROP_CAPACITY:
+ if (info->entry_factory_mode){
+ val->intval = 100;
+ info->capacity = 100;
+ } else if (info->soca->displayed_soc <= 0) {
+ val->intval = 0;
+ info->capacity = 0;
+ } else {
+ val->intval = (info->soca->displayed_soc + 50)/100;
+ info->capacity = (info->soca->displayed_soc + 50)/100;
+ }
+
+ if (critical_low_flag) {
+ uint8_t chg_sts = 0;
+ ret = ricoh61x_read(info->dev->parent, CHGSTATE_REG, &chg_sts);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the status register\n");
+ chg_sts = 0xC0;
+ }
+ if (chg_sts & 0xC0) {
+ critical_low_flag = 0;
+ } else {
+ val->intval = 0;
+ info->capacity = 0;
+ }
+ }
+
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev, "battery capacity is %d%%\n",
+ info->capacity);
+#endif
+ break;
+
+ /* current temperature of battery */
+ case POWER_SUPPLY_PROP_TEMP:
+ if (info->soca->ready_fg) {
+ ret = 0;
+ val->intval = get_battery_temp_2(info);
+ info->battery_temp = val->intval/10;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev,
+ "battery temperature is %d degree\n",
+ info->battery_temp);
+#endif
+ } else {
+ val->intval = info->battery_temp * 10;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev, "battery temperature is %d degree\n", info->battery_temp);
+#endif
+ }
+ 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;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev,
+ "time of empty battery is %d minutes\n",
+ info->time_to_empty);
+#endif
+ } else {
+ //val->intval = -EINVAL;
+ val->intval = info->time_to_empty * 60;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev, "time of empty battery is %d minutes\n", info->time_to_empty);
+#endif
+ }
+ 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;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev,
+ "time of full battery is %d minutes\n",
+ info->time_to_full);
+#endif
+ } else {
+ //val->intval = -EINVAL;
+ val->intval = info->time_to_full * 60;
+#ifdef _RICOH619_DEBUG_
+ dev_dbg(info->dev, "time of full battery is %d minutes\n", info->time_to_full);
+#endif
+ }
+ 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 ricoh61x_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 ricoh61x_power_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+struct power_supply power_ntx = {
+ .name = "mc13892_charger",
+ .type = POWER_SUPPLY_TYPE_MAINS|POWER_SUPPLY_TYPE_USB,
+ .properties = ricoh61x_power_props,
+ .num_properties = ARRAY_SIZE(ricoh61x_power_props),
+ .get_property = ricoh61x_batt_get_prop,
+};
+
+struct power_supply powerac = {
+ .name = "acpwr",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = ricoh61x_power_props,
+ .num_properties = ARRAY_SIZE(ricoh61x_power_props),
+ .get_property = ricoh61x_batt_get_prop,
+};
+
+struct power_supply powerusb = {
+ .name = "usbpwr",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = ricoh61x_power_props,
+ .num_properties = ARRAY_SIZE(ricoh61x_power_props),
+ .get_property = ricoh61x_batt_get_prop,
+};
+
+static __devinit int ricoh61x_battery_probe(struct platform_device *pdev)
+{
+ struct ricoh61x_battery_info *info;
+ struct ricoh619_battery_platform_data *pdata;
+ int type_n;
+ int ret, temp;
+
+ printk(KERN_EMERG "PMU: %s : version is %s\n", __func__,RICOH61x_BATTERY_VERSION);
+
+ info = kzalloc(sizeof(struct ricoh61x_battery_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->soca = kzalloc(sizeof(struct ricoh61x_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;
+
+ /* check rage of b,.attery type */
+ type_n = Battery_Type();
+ temp = sizeof(pdata->type)/(sizeof(struct ricoh619_battery_type_data));
+ if(type_n >= temp)
+ {
+ printk("%s : Battery type num is out of range\n", __func__);
+ type_n = 0;
+ }
+ printk("%s type_n=%d,temp is %d\n", __func__, type_n,temp);
+
+ /* check rage of battery num */
+ info->num = Battery_Table();
+ temp = sizeof(battery_init_para)/(sizeof(uint8_t)*32);
+ if(info->num >= (sizeof(battery_init_para)/(sizeof(uint8_t)*32)))
+ {
+ printk("%s : Battery num is out of range\n", __func__);
+ info->num = 0;
+ }
+ printk("%s info->num=%d,temp is %d\n", __func__, info->num,temp);
+
+ /* these valuse are set in platform */
+ info->ch_vfchg = pdata->type[type_n].ch_vfchg;
+ info->ch_vrchg = pdata->type[type_n].ch_vrchg;
+ info->ch_vbatovset = pdata->type[type_n].ch_vbatovset;
+ info->ch_ichg = pdata->type[type_n].ch_ichg;
+ info->ch_ilim_adp = pdata->type[type_n].ch_ilim_adp;
+ info->ch_ilim_usb = pdata->type[type_n].ch_ilim_usb;
+ info->ch_icchg = pdata->type[type_n].ch_icchg;
+ info->fg_target_vsys = pdata->type[type_n].fg_target_vsys;
+ info->fg_target_ibat = pdata->type[type_n].fg_target_ibat;
+ info->fg_poff_vbat = pdata->type[type_n].fg_poff_vbat;
+ info->jt_en = pdata->type[type_n].jt_en;
+ info->jt_hw_sw = pdata->type[type_n].jt_hw_sw;
+ info->jt_temp_h = pdata->type[type_n].jt_temp_h;
+ info->jt_temp_l = pdata->type[type_n].jt_temp_l;
+ info->jt_vfchg_h = pdata->type[type_n].jt_vfchg_h;
+ info->jt_vfchg_l = pdata->type[type_n].jt_vfchg_l;
+ info->jt_ichg_h = pdata->type[type_n].jt_ichg_h;
+ info->jt_ichg_l = pdata->type[type_n].jt_ichg_l;
+
+ /*
+ printk("%s setting value\n", __func__);
+ printk("%s info->ch_vfchg = 0x%x\n", __func__, info->ch_vfchg);
+ printk("%s info->ch_vrchg = 0x%x\n", __func__, info->ch_vrchg);
+ printk("%s info->ch_vbatovset =0x%x\n", __func__, info->ch_vbatovset);
+ printk("%s info->ch_ichg = 0x%x\n", __func__, info->ch_ichg);
+ printk("%s info->ch_ilim_adp =0x%x \n", __func__, info->ch_ilim_adp);
+ printk("%s info->ch_ilim_usb = 0x%x\n", __func__, info->ch_ilim_usb);
+ printk("%s info->ch_icchg = 0x%x\n", __func__, info->ch_icchg);
+ printk("%s info->fg_target_vsys = 0x%x\n", __func__, info->fg_target_vsys);
+ printk("%s info->fg_target_ibat = 0x%x\n", __func__, info->fg_target_ibat);
+ printk("%s info->jt_en = 0x%x\n", __func__, info->jt_en);
+ printk("%s info->jt_hw_sw = 0x%x\n", __func__, info->jt_hw_sw);
+ printk("%s info->jt_temp_h = 0x%x\n", __func__, info->jt_temp_h);
+ printk("%s info->jt_temp_l = 0x%x\n", __func__, info->jt_temp_l);
+ printk("%s info->jt_vfchg_h = 0x%x\n", __func__, info->jt_vfchg_h);
+ printk("%s info->jt_vfchg_l = 0x%x\n", __func__, info->jt_vfchg_l);
+ printk("%s info->jt_ichg_h = 0x%x\n", __func__, info->jt_ichg_h);
+ printk("%s info->jt_ichg_l = 0x%x\n", __func__, info->jt_ichg_l);
+ */
+
+ 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;
+ info->suspend_state = false;
+ info->stop_disp = false;
+
+ mutex_init(&info->lock);
+ platform_set_drvdata(pdev, info);
+
+// info->battery.name = "battery";
+ info->battery.name = "mc13892_bat";
+ info->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ info->battery.properties = ricoh61x_batt_props;
+ info->battery.num_properties = ARRAY_SIZE(ricoh61x_batt_props);
+ info->battery.get_property = ricoh61x_batt_get_prop;
+ info->battery.set_property = NULL;
+ info->battery.external_power_changed
+ = ricoh61x_external_power_changed;
+
+ /* Disable Charger/ADC interrupt */
+ ret = ricoh61x_clr_bits(info->dev->parent, RICOH61x_INTC_INTEN,
+ CHG_INT | ADC_INT);
+ if (ret)
+ goto out;
+
+ ret = ricoh61x_init_battery(info);
+ if (ret)
+ goto out;
+
+#ifdef ENABLE_FACTORY_MODE
+ info->factory_mode_wqueue
+ = create_singlethread_workqueue("ricoh61x_factory_mode");
+ INIT_DELAYED_WORK_DEFERRABLE(&info->factory_mode_work,
+ check_charging_state_work);
+
+ ret = ricoh61x_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);
+ ret = power_supply_register(&pdev->dev, &power_ntx);
+
+ info->monitor_wqueue
+ = create_singlethread_workqueue("ricoh61x_battery_monitor");
+ info->workqueue = create_singlethread_workqueue("r5t61x_charger_in");
+ INIT_WORK(&info->irq_work, charger_irq_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->monitor_work,
+ ricoh61x_battery_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->displayed_work,
+ ricoh61x_displayed_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->charge_stable_work,
+ ricoh61x_stable_charge_countdown_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->charge_monitor_work,
+ ricoh61x_charge_monitor_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->get_charge_work,
+ ricoh61x_get_charge_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->jeita_work, ricoh61x_jeita_work);
+ INIT_DELAYED_WORK(&info->changed_work, ricoh61x_changed_work);
+
+ /* Charger IRQ workqueue settings */
+ charger_irq = pdata->irq;
+
+
+ ret = request_threaded_irq(charger_irq + RICOH61x_IRQ_FONCHGINT,
+ NULL, charger_in_isr, IRQF_ONESHOT,
+ "r5t61x_charger_in", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't get CHG_INT IRQ for chrager: %d\n",
+ ret);
+ goto out;
+ }
+
+ ret = request_threaded_irq(charger_irq + RICOH61x_IRQ_FCHGCMPINT,
+ NULL, charger_complete_isr,
+ IRQF_ONESHOT, "r5t61x_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 + RICOH61x_IRQ_FVUSBDETSINT,
+ NULL, charger_usb_isr, IRQF_ONESHOT,
+ "r5t61x_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 + RICOH61x_IRQ_FVADPDETSINT,
+ NULL, charger_adp_isr, IRQF_ONESHOT,
+ "r5t61x_adp_det", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Can't get ADP_DET IRQ for chrager: %d\n", ret);
+ goto out;
+ }
+
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+// ret = request_threaded_irq(charger_irq + RICOH61x_IRQ_VSYSLIR,
+// NULL, adc_vsysl_isr, IRQF_ONESHOT,
+// "r5t61x_adc_vsysl", info);
+ ret = request_threaded_irq(charger_irq + RICOH61x_IRQ_VBATLIR,
+ NULL, adc_vsysl_isr, IRQF_ONESHOT,
+ "r5t61x_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
+
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+ ret = request_threaded_irq(charger_irq + RICOH61x_IRQ_VTHMLIR,
+ NULL, adc_vtherm_isr, IRQF_ONESHOT,
+ "r5t61x_adc_vtherm", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Can't get ADC_VTHML IRQ for chrager: %d\n", ret);
+ goto out;
+ }
+
+ ret = request_threaded_irq(charger_irq + RICOH61x_IRQ_VTHMHIR,
+ NULL, adc_vtherm_isr, IRQF_ONESHOT,
+ "r5t61x_adc_vtherm", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Can't get ADC_VTHMH IRQ for chrager: %d\n", ret);
+ goto out;
+ }
+
+ INIT_DELAYED_WORK_DEFERRABLE(&info->battery_temp_work,
+ battery_temp_irq_work);
+#endif
+
+ /* Charger init and IRQ setting */
+ ret = ricoh61x_init_charger(info);
+ if (ret)
+ goto out;
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+ ret = ricoh61x_init_fgsoca(info);
+#endif
+ queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+ RICOH61x_MONITOR_START_TIME*HZ);
+
+
+ /* Enable Charger/ADC interrupt */
+ ricoh61x_set_bits(info->dev->parent, RICOH61x_INTC_INTEN, CHG_INT | ADC_INT);
+
+// if(sysfs_create_link(&info->battery.dev->kobj, &info->battery.dev->kobj, "mc13892_bat")) {
+// printk("[%s-%d] create mc13892_bat link fail !\n", __func__, __LINE__);
+// }
+ if(sysfs_create_link(&info->dev->parent->parent->parent->parent->kobj, &info->dev->kobj, "pmic_battery.1")) {
+ printk("[%s-%d] create pmic_battery.1 link fail !\n", __func__, __LINE__);
+ }
+
+ return 0;
+
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit ricoh61x_battery_remove(struct platform_device *pdev)
+{
+ struct ricoh61x_battery_info *info = platform_get_drvdata(pdev);
+ uint8_t val;
+ int ret;
+ int err;
+ int cc_cap = 0;
+ long cc_cap_mas = 0;
+ bool is_charging = true;
+
+ if (g_fg_on_mode
+ && (info->soca->status == RICOH61x_SOCA_STABLE)) {
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, 0x7f);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ g_soc = 0x7f;
+ set_current_time2register(info);
+
+ } else if (info->soca->status != RICOH61x_SOCA_START
+ && info->soca->status != RICOH61x_SOCA_UNSTABLE
+ && info->soca->rsoc_ready_flag != 0) {
+ if (info->soca->displayed_soc < 50) {
+ val = 1;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ }
+ ret = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = val;
+ set_current_time2register(info);
+
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ }
+
+ if (g_fg_on_mode == 0) {
+ ret = ricoh61x_clr_bits(info->dev->parent,
+ FG_CTRL_REG, 0x01);
+ if (ret < 0)
+ dev_err(info->dev, "Error in clr FG EN\n");
+ }
+
+ /* set rapid timer 300 min */
+ err = ricoh61x_set_bits(info->dev->parent, TIMSET_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ }
+
+ free_irq(charger_irq + RICOH61x_IRQ_FONCHGINT, &info);
+ free_irq(charger_irq + RICOH61x_IRQ_FCHGCMPINT, &info);
+ free_irq(charger_irq + RICOH61x_IRQ_FVUSBDETSINT, &info);
+ free_irq(charger_irq + RICOH61x_IRQ_FVADPDETSINT, &info);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+// free_irq(charger_irq + RICOH61x_IRQ_VSYSLIR, &info);
+ free_irq(charger_irq + RICOH61x_IRQ_VADPLIR, &info);
+#endif
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+ free_irq(charger_irq + RICOH61x_IRQ_VTHMLIR, &info);
+ free_irq(charger_irq + RICOH61x_IRQ_VTHMHIR, &info);
+#endif
+
+
+ cancel_delayed_work(&info->monitor_work);
+ cancel_delayed_work(&info->charge_stable_work);
+ cancel_delayed_work(&info->charge_monitor_work);
+ cancel_delayed_work(&info->get_charge_work);
+ cancel_delayed_work(&info->displayed_work);
+ cancel_delayed_work(&info->changed_work);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ cancel_delayed_work(&info->low_battery_work);
+#endif
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+ cancel_delayed_work(&info->battery_temp_work);
+#endif
+#ifdef ENABLE_FACTORY_MODE
+ cancel_delayed_work(&info->factory_mode_work);
+#endif
+ cancel_delayed_work(&info->jeita_work);
+ cancel_work_sync(&info->irq_work);
+
+ flush_workqueue(info->monitor_wqueue);
+ flush_workqueue(info->workqueue);
+#ifdef ENABLE_FACTORY_MODE
+ flush_workqueue(info->factory_mode_wqueue);
+#endif
+
+ destroy_workqueue(info->monitor_wqueue);
+ destroy_workqueue(info->workqueue);
+#ifdef ENABLE_FACTORY_MODE
+ destroy_workqueue(info->factory_mode_wqueue);
+#endif
+
+ power_supply_unregister(&info->battery);
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+extern void ricoh_suspend_state_sync(void);
+static int ricoh61x_battery_suspend(struct device *dev)
+{
+ struct ricoh61x_battery_info *info = dev_get_drvdata(dev);
+ uint8_t val;
+ uint8_t val2;
+ int ret;
+ int err;
+ int cc_display2suspend = 0;
+ int cc_cap = 0;
+ long cc_cap_mas =0;
+ bool is_charging = true;
+ int displayed_soc_temp;
+
+ printk("PMU: %s START ================================================================================\n", __func__);
+ ricoh_suspend_state_sync();
+
+ get_current_time(info, &info->sleepEntryTime);
+ dev_info(info->dev, "sleep entry time : %lu secs\n",
+ info->sleepEntryTime);
+
+#ifdef ENABLE_MASKING_INTERRUPT_IN_SLEEP
+ ricoh61x_clr_bits(dev->parent, RICOH61x_INTC_INTEN, CHG_INT);
+#endif
+ info->stop_disp = true;
+ info->soca->suspend_full_flg = false;
+
+ if (g_fg_on_mode
+ && (info->soca->status == RICOH61x_SOCA_STABLE)) {
+ err = ricoh61x_write(info->dev->parent, PSWR_REG, 0x7f);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ g_soc = 0x7F;
+ set_current_time2register(info);
+
+ info->soca->suspend_soc = info->soca->displayed_soc;
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ info->soca->suspend_cc = 0;
+
+ } else {
+ if(info->soca->status == RICOH61x_SOCA_LOW_VOL){
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ if(is_charging == true){
+ info->soca->cc_delta = cc_cap;
+ //cc_cap_mas;
+ }else {
+ info->soca->cc_delta = -cc_cap;
+ cc_cap_mas = -cc_cap_mas;
+ }
+
+ info->soca->temp_cc_delta_cap_mas += cc_cap_mas - info->soca->last_cc_delta_cap_mas;
+
+ printk("PMU : %s : Suspend : temp_cc_delta_cap_mas is %ld, cc_delta is %ld, last_cc_delta_cap_mas is %ld\n"
+ ,__func__, info->soca->temp_cc_delta_cap_mas, cc_cap_mas, info->soca->last_cc_delta_cap_mas);
+ displayed_soc_temp = info->soca->displayed_soc;
+
+ if ((info->soca->displayed_soc + 50)/100 >= 100) {
+ displayed_soc_temp = min(10000, displayed_soc_temp);
+ } else {
+ displayed_soc_temp = min(9949, displayed_soc_temp);
+ }
+ displayed_soc_temp = max(0, displayed_soc_temp);
+ info->soca->displayed_soc = displayed_soc_temp;
+
+ info->soca->suspend_soc = info->soca->displayed_soc;
+ info->soca->suspend_cc = 0;
+ info->soca->suspend_rsoc = calc_capacity_2(info);
+
+ }else if (info->soca->rsoc_ready_flag == 0
+ || info->soca->status == RICOH61x_SOCA_START
+ || info->soca->status == RICOH61x_SOCA_UNSTABLE) {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 2);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ if(is_charging == true){
+ info->soca->cc_delta = cc_cap;
+ //cc_cap_mas;
+ }else {
+ info->soca->cc_delta = -cc_cap;
+ cc_cap_mas = -cc_cap_mas;
+ }
+
+ //info->soca->temp_cc_delta_cap_mas += cc_cap_mas - info->soca->last_cc_delta_cap_mas;
+
+ //get charge/discharge value from displayed work to suspend start
+ cc_display2suspend = info->soca->cc_delta - info->soca->last_cc_rrf0;
+ cc_display2suspend = min(400, cc_display2suspend); //fail-safe
+ cc_display2suspend = max(-400, cc_display2suspend);
+ info->soca->last_cc_rrf0 = 0;
+
+ printk("PMU : %s : Suspend : temp_cc_delta_cap_mas is %ld, cc_delta is %ld, last_cc_delta_cap_mas is %ld, cc_display2suspend is %d\n"
+ ,__func__, info->soca->temp_cc_delta_cap_mas, cc_cap_mas, info->soca->last_cc_delta_cap_mas, cc_display2suspend);
+
+ if (info->soca->status == RICOH61x_SOCA_START
+ || info->soca->status == RICOH61x_SOCA_UNSTABLE
+ || info->soca->status == RICOH61x_SOCA_STABLE) {
+ displayed_soc_temp
+ = info->soca->init_pswr * 100 + info->soca->cc_delta;
+ } else {
+ if(info->soca->status == RICOH61x_SOCA_FULL){
+ info->soca->temp_cc_delta_cap += cc_display2suspend;
+ displayed_soc_temp
+ = info->soca->displayed_soc;// + (info->soca->cc_delta/100) *100;
+ } else {
+ displayed_soc_temp
+ = info->soca->displayed_soc + cc_display2suspend;
+ }
+ }
+
+ if ((info->soca->displayed_soc + 50)/100 >= 100) {
+ displayed_soc_temp = min(10000, displayed_soc_temp);
+ } else {
+ displayed_soc_temp = min(9949, displayed_soc_temp);
+ }
+ displayed_soc_temp = max(0, displayed_soc_temp);
+ info->soca->displayed_soc = displayed_soc_temp;
+
+ info->soca->suspend_soc = info->soca->displayed_soc;
+ info->soca->suspend_cc = info->soca->cc_delta % 100;
+
+ val = info->soca->init_pswr + (info->soca->cc_delta/100);
+ val = min(100, val);
+ val = max(1, val);
+
+ info->soca->init_pswr = val;
+ info->soca->suspend_rsoc = (info->soca->init_pswr * 100) + (info->soca->cc_delta % 100);
+
+ } else {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ if(is_charging == true){
+ info->soca->cc_delta = cc_cap;
+ //cc_cap_mas;
+ }else {
+ info->soca->cc_delta = -cc_cap;
+ cc_cap_mas = -cc_cap_mas;
+ }
+
+ //info->soca->temp_cc_delta_cap_mas += cc_cap_mas - info->soca->last_cc_delta_cap_mas;
+ printk("PMU : %s : Suspend : temp_cc_delta_cap_mas is %ld, cc_delta is %ld, last_cc_delta_cap_mas is %ld\n"
+ ,__func__, info->soca->temp_cc_delta_cap_mas, cc_cap_mas, info->soca->last_cc_delta_cap_mas);
+
+ if (info->soca->status == RICOH61x_SOCA_FULL){
+ info->soca->temp_cc_delta_cap += info->soca->cc_delta;
+ displayed_soc_temp = info->soca->displayed_soc;
+ } else {
+ displayed_soc_temp
+ = info->soca->displayed_soc + info->soca->cc_delta;
+ }
+
+ if ((info->soca->displayed_soc + 50)/100 >= 100) {
+ displayed_soc_temp = min(10000, displayed_soc_temp);
+ } else {
+ displayed_soc_temp = min(9949, displayed_soc_temp);
+ }
+ displayed_soc_temp = max(0, displayed_soc_temp);
+ info->soca->displayed_soc = displayed_soc_temp;
+
+ info->soca->suspend_soc = info->soca->displayed_soc;
+ info->soca->suspend_cc = 0;
+ info->soca->suspend_rsoc = calc_capacity_2(info);
+
+ }
+
+ printk(KERN_INFO "PMU: %s status(%d), rrf(%d), suspend_soc(%d), suspend_cc(%d)\n",
+ __func__, info->soca->status, info->soca->rsoc_ready_flag, info->soca->suspend_soc, info->soca->suspend_cc);
+ printk(KERN_INFO "PMU: %s DSOC(%d), init_pswr(%d), cc_delta(%d)\n",
+ __func__, info->soca->displayed_soc, info->soca->init_pswr, info->soca->cc_delta);
+
+ if (info->soca->displayed_soc < 50) {
+ val = 1;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ }
+ ret = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = val;
+ set_current_time2register(info);
+
+ }
+
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 0);
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+
+ printk(KERN_INFO "PMU: %s : STATUS(%d), DSOC(%d), RSOC(%d), init_pswr*100(%d), cc_delta(%d) ====================\n",
+ __func__, info->soca->status, displayed_soc_temp,
+ calc_capacity_2(info), info->soca->init_pswr*100, info->soca->cc_delta);
+
+ if (info->soca->status == RICOH61x_SOCA_DISP
+ || info->soca->status == RICOH61x_SOCA_STABLE
+ || info->soca->status == RICOH61x_SOCA_FULL) {
+ info->soca->soc = calc_capacity_2(info);
+ info->soca->soc_delta =
+ info->soca->soc_delta + (info->soca->soc - info->soca->last_soc);
+
+ } else {
+ info->soca->soc_delta = 0;
+ }
+
+ if (info->soca->status == RICOH61x_SOCA_FULL)
+ {
+ info->soca->suspend_full_flg = true;
+ info->soca->status = RICOH61x_SOCA_DISP;
+ }
+
+ if (info->soca->status == RICOH61x_SOCA_LOW_VOL)
+ {
+ //reset current information
+ info->soca->hurry_up_flg = 0;
+ }
+
+ info->soca->store_fl_current = fl_current;
+ info->soca->store_slp_state = slp_state;
+ info->soca->store_sus_current = sus_current;
+ info->soca->store_hiber_current = hiber_current;
+
+ printk(KERN_INFO "PMU: %s : fl_current(%d), slp_state(%d), sus_current(%d), hiber_current(%d)\n",
+ __func__, info->soca->store_fl_current, info->soca->store_slp_state,
+ info->soca->store_sus_current, info->soca->store_hiber_current);
+
+ /* set rapid timer 300 min */
+ err = ricoh61x_set_bits(info->dev->parent, TIMSET_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ }
+
+ /* Enable VBAT threshold Low interrupt */
+ err = ricoh61x_set_bits(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x02);
+ if (err < 0) {
+ dev_err(info->dev, "Error in settind VBAT ThrLow\n");
+ }
+ info->suspend_state = true;
+
+ //Enable relaxtion state
+ /* set relaxation state */
+ if (RICOH61x_REL1_SEL_VALUE > 240)
+ val = 0x0F;
+ else
+ val = RICOH61x_REL1_SEL_VALUE / 16 ;
+
+ /* set relaxation state */
+ if (RICOH61x_REL2_SEL_VALUE > 120)
+ val2 = 0x0F;
+ else
+ val2 = RICOH61x_REL2_SEL_VALUE / 8 ;
+
+ val = val + (val2 << 4);
+
+ err = ricoh61x_write_bank1(info->dev->parent, BAT_REL_SEL_REG, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing BAT_REL_SEL_REG\n");
+ }
+
+
+ cancel_delayed_work(&info->monitor_work);
+ cancel_delayed_work(&info->displayed_work);
+ cancel_delayed_work(&info->charge_stable_work);
+ cancel_delayed_work(&info->charge_monitor_work);
+ cancel_delayed_work(&info->get_charge_work);
+ cancel_delayed_work(&info->changed_work);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ cancel_delayed_work(&info->low_battery_work);
+#endif
+#ifdef ENABLE_BATTERY_TEMP_DETECTION
+ cancel_delayed_work(&info->battery_temp_work);
+#endif
+#ifdef ENABLE_FACTORY_MODE
+ cancel_delayed_work(&info->factory_mode_work);
+#endif
+ cancel_delayed_work(&info->jeita_work);
+/* flush_work(&info->irq_work); */
+
+ return 0;
+}
+
+/**
+* get SOC value during period of Suspend/Hibernation
+* this function is only run discharge state
+* info : battery info
+* Period : sleep period
+* sleepCurrent : sleep current
+*
+* return value : delta soc, unit is "minus" 0.01%
+*/
+
+static int calc_cc_value_by_sleepPeriod(struct ricoh61x_battery_info *info, unsigned long Period, int sleepCurrent)
+{
+ int fa_cap; //unit is mAh
+ unsigned long delta_cap; //unit is uAs
+ unsigned long delta_soc; //unit is 0.01%
+
+ fa_cap = (battery_init_para[info->num][22]<<8)
+ | (battery_init_para[info->num][23]);
+
+ if(fa_cap == 0){
+ // avoiding 0 divied
+ return 0;
+ } else {
+ // Check Suspend current is normal
+
+ // delta_cap[uAs] = Period[s] * (Suspend current + FL current)[uA]
+ delta_cap = (Period * sleepCurrent) + info->soca->sus_cc_cap_offset;
+ //delta_soc[0.01%] = (delta_cap/1000)[mAs] * 10000/ (fa_cap * 60 * 60)[mAs];
+ delta_soc = (delta_cap / (fa_cap * 36)) / 10;
+
+ //info->soca->sus_cc_cap_offset[uAs] = delta_cap[uAs] - (delta_soc[0.01%] * (fa_cap[mAs] * 60 * 60/ (100 * 100)))*1000;
+ info->soca->sus_cc_cap_offset = delta_cap - (delta_soc * (fa_cap * 360));
+ //0.01% uAs => fa_cap*360
+ info->soca->sus_cc_cap_offset = min((360*fa_cap), info->soca->sus_cc_cap_offset);
+ info->soca->sus_cc_cap_offset = max(0, info->soca->sus_cc_cap_offset);
+
+ delta_soc = min(10000, delta_soc);
+ delta_soc = max(0, delta_soc);
+
+ printk("PMU : %s : delta_cap is %ld [uAs], Period is %ld [s], fa_cap is %d [mAh], delta_soc is %ld [0.01%%], offset is %d [uAs]\n"
+ ,__func__, delta_cap, Period, fa_cap, delta_soc, info->soca->sus_cc_cap_offset);
+ }
+
+ return (-1 * delta_soc);
+}
+
+/**
+* get SOC value during period of Suspend/Hibernate with current method
+* info : battery info
+* Period : sleep period
+*
+* return value : soc, unit is 0.01%
+*/
+
+static int calc_soc_by_currentMethod(struct ricoh61x_battery_info *info, unsigned long Period)
+{
+ int soc;
+ int sleepCurrent; // unit is uA
+
+ if(info->soca->store_slp_state == 0) {
+ // Check Suspend current is normal
+ if ((info->soca->store_sus_current <= 0)
+ || (info->soca->store_sus_current > RICOH61x_SLEEP_CURRENT_LIMIT)) {
+ if ((sus_current <= 0) || (sus_current > RICOH61x_SLEEP_CURRENT_LIMIT)) {
+ info->soca->store_sus_current = RICOH61x_SUS_CURRENT_DEF;
+ } else {
+ info->soca->store_sus_current = sus_current;
+ }
+ }
+
+ if ((info->soca->store_fl_current < 0)
+ || (info->soca->store_fl_current > RICOH61x_FL_CURRENT_LIMIT)) {
+ if ((fl_current < 0) || (fl_current > RICOH61x_FL_CURRENT_LIMIT)) {
+ info->soca->store_fl_current = RICOH61x_FL_CURRENT_DEF;
+ } else {
+ info->soca->store_fl_current = fl_current;
+ }
+ }
+
+ sleepCurrent = info->soca->store_sus_current + info->soca->store_fl_current;
+
+ if (sleepCurrent < RICOH61x_SUS_CURRENT_THRESH) {
+ // Calculate cc_delta from [Suspend current * Sleep period]
+ info->soca->cc_delta = calc_cc_value_by_sleepPeriod(info, Period, sleepCurrent);
+ printk(KERN_INFO "PMU: %s Suspend(S/W) slp_current(%d), sus_current(%d), fl_current(%d), cc_delta(%d) ----------\n",
+ __func__, sleepCurrent, info->soca->store_sus_current, info->soca->store_fl_current, info->soca->cc_delta);
+ } else {
+ // Calculate cc_delta between Sleep-In and Sleep-Out
+ info->soca->cc_delta -= info->soca->suspend_cc;
+ printk(KERN_INFO "PMU: %s Suspend(H/W) slp_current(%d), sus_current(%d), fl_current(%d), cc_delta(%d) ----------\n",
+ __func__, sleepCurrent, info->soca->store_sus_current, info->soca->store_fl_current, info->soca->cc_delta);
+ }
+ } else {
+ // Check Hibernate current is normal
+ if ((info->soca->store_hiber_current <= 0)
+ || (info->soca->store_hiber_current > RICOH61x_SLEEP_CURRENT_LIMIT)) {
+ if ((hiber_current <= 0) || (hiber_current > RICOH61x_SLEEP_CURRENT_LIMIT)) {
+ sleepCurrent = RICOH61x_HIBER_CURRENT_DEF;
+ } else {
+ sleepCurrent = hiber_current;
+ }
+ } else {
+ sleepCurrent = info->soca->store_hiber_current;
+ }
+ // Calculate cc_delta from [Hibernate current * Sleep period]
+ info->soca->cc_delta = calc_cc_value_by_sleepPeriod(info, Period, sleepCurrent);
+ printk(KERN_INFO "PMU: %s Hibernate(S/W) hiber_current(%d), cc_delta(%d) ----------\n",
+ __func__, sleepCurrent, info->soca->cc_delta);
+ }
+
+ soc = info->soca->suspend_soc + info->soca->cc_delta;
+
+ printk("PMU : %s : slp_state is %d, soc is %d [0.01%%] ----------\n"
+ , __func__, info->soca->store_slp_state, soc);
+
+ // soc range is 0~10000
+ return soc;
+}
+
+
+static int ricoh61x_battery_resume(struct device *dev)
+{
+ struct ricoh61x_battery_info *info = dev_get_drvdata(dev);
+ uint8_t val;
+ int ret;
+ int displayed_soc_temp;
+ int cc_cap = 0;
+ long cc_cap_mas = 0;
+ bool is_charging = true;
+ bool is_jeita_updated;
+ int i;
+ unsigned long suspend_period_time; //unit is sec
+ int soc_voltage, soc_current;
+ int resume_rsoc;
+
+ printk("PMU: %s START ================================================================================\n", __func__);
+
+ get_current_time(info, &info->sleepExitTime);
+ dev_info(info->dev, "sleep exit time : %lu secs\n",
+ info->sleepExitTime);
+
+ suspend_period_time = info->sleepExitTime - info->sleepEntryTime;
+
+#ifdef STANDBY_MODE_DEBUG
+ if(multiple_sleep_mode == 0) {
+// suspend_period_time *= 1;
+ } else if(multiple_sleep_mode == 1) {
+ suspend_period_time *= 60;
+ } else if(multiple_sleep_mode == 2) {
+ suspend_period_time *= 3600;
+ }
+#endif
+
+ printk("PMU : %s : suspend_period_time is %lu, sleepExitTime is %lu sleepEntryTime is %lu ==========\n",
+ __func__, suspend_period_time,info->sleepExitTime,info->sleepEntryTime);
+
+ /* Clear VBAT threshold Low interrupt */
+ ret = ricoh61x_clr_bits(info->dev->parent, RICOH61x_INT_EN_ADC1, 0x02);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in clearing VBAT ThrLow\n");
+ }
+
+
+#ifdef ENABLE_MASKING_INTERRUPT_IN_SLEEP
+ ricoh61x_set_bits(dev->parent, RICOH61x_INTC_INTEN, CHG_INT);
+#endif
+ ret = check_jeita_status(info, &is_jeita_updated);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in updating JEITA %d\n", ret);
+ }
+
+ if (info->entry_factory_mode) {
+ info->soca->displayed_soc = -EINVAL;
+ } else {
+ info->soca->soc = info->soca->suspend_soc + info->soca->suspend_cc;
+
+ if (RICOH61x_SOCA_START == info->soca->status
+ || RICOH61x_SOCA_UNSTABLE == info->soca->status
+ || info->soca->rsoc_ready_flag == 0) {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 2);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+
+ //this is for CC delta issue for Hibernate
+ if((info->soca->cc_delta - info->soca->suspend_cc) <= 0){
+ // Discharge Processing
+ printk(KERN_INFO "PMU: %s : Discharge Processing (rrf=0)\n", __func__);
+
+ // Calculate SOC by Current Method
+ soc_current = calc_soc_by_currentMethod(info, suspend_period_time);
+
+ // Calculate SOC by Voltage Method
+ soc_voltage = calc_soc_by_voltageMethod(info);
+
+ printk(KERN_INFO "PMU: %s : soc_current(%d), soc_voltage(%d), Diff(%d) ==========\n",
+ __func__, soc_current, soc_voltage, (soc_current - soc_voltage));
+
+ // If difference is small, use current method. If not, use voltage method.
+ if ((soc_current - soc_voltage) < 1000) {
+ // Use Current method if difference is small
+ displayed_soc_temp = soc_current;
+ update_rsoc_on_currentMethod(info, soc_current);
+ } else {
+ // Use Voltage method if difference is large
+ displayed_soc_temp = soc_voltage;
+ update_rsoc_on_voltageMethod(info, soc_voltage);
+ }
+ } else {
+ // Charge Processing
+ val = info->soca->init_pswr + (info->soca->cc_delta/100);
+ val = min(100, val);
+ val = max(1, val);
+
+ info->soca->init_pswr = val;
+
+ if (RICOH61x_SOCA_START == info->soca->status
+ || RICOH61x_SOCA_UNSTABLE == info->soca->status
+ || RICOH61x_SOCA_STABLE == info->soca->status) {
+// displayed_soc_temp = info->soca->suspend_soc + info->soca->cc_delta;
+ displayed_soc_temp = (info->soca->init_pswr*100) + info->soca->cc_delta%100;
+ } else {
+ info->soca->cc_delta = info->soca->cc_delta - info->soca->suspend_cc;
+ if ((info->soca->cc_delta < 400) && (info->soca->suspend_full_flg == true)){
+ displayed_soc_temp = info->soca->suspend_soc;
+ info->soca->temp_cc_delta_cap += info->soca->cc_delta;
+ info->soca->cc_delta = info->soca->suspend_cc;
+ printk("PMU: %s : under 400 cc_delta is %d, temp_cc_delta is %d\n",
+ __func__, info->soca->cc_delta, info->soca->temp_cc_delta_cap);
+ }else {
+ displayed_soc_temp = info->soca->suspend_soc + info->soca->cc_delta;
+ info->soca->temp_cc_delta_cap = 0;
+ }
+ }
+ }
+
+ } else {
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 1);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+
+ printk("PMU: %s cc_delta(%d), suspend_cc(%d), Diff(%d)\n",
+ __func__, info->soca->cc_delta, info->soca->suspend_cc, (info->soca->cc_delta - info->soca->suspend_cc));
+ //this is for CC delta issue for Hibernate
+ if((info->soca->cc_delta - info->soca->suspend_cc) <= 0){
+ // Discharge Processing
+ printk(KERN_INFO "PMU: %s : Discharge Processing (rrf=1)\n", __func__);
+
+ // Calculate SOC by Current Method
+ soc_current = calc_soc_by_currentMethod(info, suspend_period_time);
+
+ // Calculate SOC by Voltage Method
+ soc_voltage = calc_soc_by_voltageMethod(info);
+
+ printk(KERN_INFO "PMU: %s : soc_current(%d), soc_voltage(%d), Diff(%d)\n",
+ __func__, soc_current, soc_voltage, (soc_current - soc_voltage));
+
+ // If difference is small, use current method. If not, use voltage method.
+ if ((soc_current - soc_voltage) < 1000) {
+ // Use Current method if difference is small
+ displayed_soc_temp = soc_current;
+ update_rsoc_on_currentMethod(info, soc_current);
+ } else {
+ // Use Voltage method if difference is large
+ displayed_soc_temp = soc_voltage;
+ update_rsoc_on_voltageMethod(info, soc_voltage);
+ }
+ } else {
+ // Charge Processing
+ info->soca->cc_delta = info->soca->cc_delta - info->soca->suspend_cc;
+ if ((info->soca->cc_delta < 400) && (info->soca->suspend_full_flg == true)){
+ displayed_soc_temp = info->soca->suspend_soc;
+ info->soca->temp_cc_delta_cap += info->soca->cc_delta;
+ info->soca->cc_delta = info->soca->suspend_cc;
+ printk("PMU: %s : under 400 cc_delta is %d, temp_cc_delta is %d\n",
+ __func__, info->soca->cc_delta, info->soca->temp_cc_delta_cap);
+ }else {
+ displayed_soc_temp = info->soca->suspend_soc + info->soca->cc_delta;
+ info->soca->temp_cc_delta_cap = 0;
+ }
+ }
+ }
+
+ /* Check "zero_flg" in all states */
+ if (info->soca->zero_flg == 1) {
+ if((info->soca->Ibat_ave >= 0)
+ || (displayed_soc_temp >= 100)){
+ info->soca->zero_flg = 0;
+ } else {
+ displayed_soc_temp = 0;
+ }
+ } else if (displayed_soc_temp < 100) {
+ /* keep DSOC = 1 when Vbat is over 3.4V*/
+ if( info->fg_poff_vbat != 0) {
+ if (info->soca->Vbat_ave < 2000*1000) { /* error value */
+ displayed_soc_temp = 100;
+ } else if (info->soca->Vbat_ave < info->fg_poff_vbat*1000) {
+ displayed_soc_temp = 0;
+ info->soca->zero_flg = 1;
+ } else {
+ displayed_soc_temp = 100;
+ }
+ }
+ }
+ displayed_soc_temp = min(10000, displayed_soc_temp);
+ displayed_soc_temp = max(0, displayed_soc_temp);
+
+ if (0 == info->soca->jt_limit) {
+ check_charge_status_2(info, displayed_soc_temp);
+ } else {
+ info->soca->displayed_soc = displayed_soc_temp;
+ }
+
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ ret = ricoh61x_write(info->dev->parent, PSWR_REG, val);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = val;
+ set_current_time2register(info);
+
+
+ if ((RICOH61x_SOCA_DISP == info->soca->status)
+ || (RICOH61x_SOCA_STABLE == info->soca->status)){
+ info->soca->last_soc = calc_capacity_2(info);
+ }
+ }
+
+ ret = calc_capacity_in_period(info, &cc_cap, &cc_cap_mas,
+ &is_charging, 0);
+ if(is_charging == true) {
+ info->soca->cc_delta = cc_cap;
+ //cc_cap_mas;
+ } else {
+ info->soca->cc_delta = -cc_cap;
+ cc_cap_mas = -cc_cap_mas;
+ }
+
+ //if (info->soca->status == RICOH61x_SOCA_LOW_VOL)
+ //{
+ info->soca->last_cc_delta_cap = info->soca->cc_delta;
+ info->soca->last_cc_delta_cap_mas = cc_cap_mas;
+ //}
+
+
+
+ printk(KERN_INFO "PMU: %s : STATUS(%d), DSOC(%d), RSOC(%d), init_pswr*100(%d), cc_delta(%d) ====================\n",
+ __func__, info->soca->status, displayed_soc_temp, calc_capacity_2(info), info->soca->init_pswr*100, info->soca->cc_delta);
+
+ ret = measure_vbatt_FG(info, &info->soca->Vbat_ave);
+ ret = measure_vsys_ADC(info, &info->soca->Vsys_ave);
+ ret = measure_Ibatt_FG(info, &info->soca->Ibat_ave);
+
+ //Disable relaxtion state
+ ret = ricoh61x_write_bank1(info->dev->parent, BAT_REL_SEL_REG, 0);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing BAT_REL_SEL_REG\n");
+ }
+
+ info->stop_disp = false;
+
+ power_supply_changed(&info->battery);
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work, HZ);
+
+ if (RICOH61x_SOCA_UNSTABLE == info->soca->status) {
+ info->soca->stable_count = 10;
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH61x_FG_STABLE_TIME*HZ/10);
+ } else if (RICOH61x_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,
+ RICOH61x_FG_RESET_TIME*HZ);
+ }
+
+ queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+ info->monitor_time);
+
+ queue_delayed_work(info->monitor_wqueue, &info->charge_monitor_work,
+ RICOH61x_CHARGE_RESUME_TIME * HZ);
+
+ info->soca->chg_count = 0;
+ queue_delayed_work(info->monitor_wqueue, &info->get_charge_work,
+ RICOH61x_CHARGE_RESUME_TIME * HZ);
+ if (info->jt_en) {
+ if (!info->jt_hw_sw) {
+ queue_delayed_work(info->monitor_wqueue, &info->jeita_work,
+ RICOH61x_JEITA_UPDATE_TIME * HZ);
+ }
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops ricoh61x_battery_pm_ops = {
+ .suspend = ricoh61x_battery_suspend,
+ .resume = ricoh61x_battery_resume,
+};
+#endif
+
+static struct platform_driver ricoh61x_battery_driver = {
+ .driver = {
+ .name = "ricoh619-battery",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ricoh61x_battery_pm_ops,
+#endif
+ },
+ .probe = ricoh61x_battery_probe,
+ .remove = __devexit_p(ricoh61x_battery_remove),
+};
+
+static int __init ricoh61x_battery_init(void)
+{
+ printk(KERN_INFO "PMU: %s\n", __func__);
+ return platform_driver_register(&ricoh61x_battery_driver);
+}
+module_init(ricoh61x_battery_init);
+
+static void __exit ricoh61x_battery_exit(void)
+{
+ platform_driver_unregister(&ricoh61x_battery_driver);
+}
+module_exit(ricoh61x_battery_exit);
+
+MODULE_DESCRIPTION("RICOH R5T619 Battery driver");
+MODULE_ALIAS("platform:ricoh619-battery");
+MODULE_LICENSE("GPL");