From f28bf8262b3ba5800c1670cfaf7f7bbe0e70bd71 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Fri, 9 Aug 2013 11:46:18 +0800 Subject: [PATCH] rk3188:pmu-ricoh619:updata the drivers,modify some rtc and fg bug --- drivers/mfd/ricoh619-irq.c | 46 +- drivers/power/ricoh619-battery.c | 1019 +++++++++++++++++++----- drivers/regulator/ricoh619-regulator.c | 2 +- drivers/rtc/rtc-ricoh619.c | 700 ++++++++++++---- include/linux/power/ricoh619_battery.h | 5 + include/linux/rtc/rtc-ricoh619.h | 10 +- 6 files changed, 1420 insertions(+), 362 deletions(-) mode change 100644 => 100755 drivers/rtc/rtc-ricoh619.c mode change 100755 => 100644 include/linux/power/ricoh619_battery.h diff --git a/drivers/mfd/ricoh619-irq.c b/drivers/mfd/ricoh619-irq.c index 32c713873b55..5bf56f136ffd 100644 --- a/drivers/mfd/ricoh619-irq.c +++ b/drivers/mfd/ricoh619-irq.c @@ -372,9 +372,9 @@ static irqreturn_t ricoh619_irq(int irq, void *data) } if (i != 2) { ret = ricoh619_write(ricoh619->dev, - irq_clr_add[i], ~int_sts[i]); + irq_clr_add[i], ~int_sts[i]); if (ret < 0) { - dev_err(ricoh619->dev, "Error in reading reg 0x%02x " + dev_err(ricoh619->dev, "Error in writing reg 0x%02x " "error: %d\n", irq_clr_add[i], ret); } } @@ -438,6 +438,7 @@ int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq, int irq_base) { int i, ret; + u8 reg_data = 0; if (!irq_base) { dev_warn(ricoh619->dev, "No interrupt support on IRQ base\n"); @@ -447,10 +448,21 @@ int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq, mutex_init(&ricoh619->irq_lock); /* Initialize all locals to 0 */ - for (i = 0; i < 8; i++) { + for (i = 0; i < 2; i++) { ricoh619->irq_en_cache[i] = 0; ricoh619->irq_en_reg[i] = 0; } + + /* Initialize rtc */ + ricoh619->irq_en_cache[2] = 0x20; + ricoh619->irq_en_reg[2] = 0x20; + + /* Initialize all locals to 0 */ + for (i = 3; i < 8; i++) { + ricoh619->irq_en_cache[i] = 0; + ricoh619->irq_en_reg[i] = 0; + } + // Charger Mask register must be set to 1 for masking Int output. for (i = 8; i < MAX_INTERRUPT_MASKS; i++) { ricoh619->irq_en_cache[i] = 0xff; @@ -490,11 +502,29 @@ int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq, /* Clear all interrupts in case they woke up active. */ for (i = 0; i < MAX_INTERRUPT_MASKS; i++) { - ret = ricoh619_write(ricoh619->dev, + if(irq_clr_add[i] != RICOH619_INT_IR_RTC) + { + ret = ricoh619_write(ricoh619->dev, irq_clr_add[i], 0); - if (ret < 0) - dev_err(ricoh619->dev, "Error in writing reg 0x%02x " - "error: %d\n", irq_clr_add[i], ret); + if (ret < 0) + dev_err(ricoh619->dev, "Error in writing reg 0x%02x " + "error: %d\n", irq_clr_add[i], ret); + } + else + { + ret = ricoh619_read(ricoh619->dev, + RICOH619_INT_IR_RTC, ®_data); + if (ret < 0) + dev_err(ricoh619->dev, "Error in reading reg 0x%02x " + "error: %d\n", RICOH619_INT_IR_RTC, ret); + reg_data &= 0xf0; + ret = ricoh619_write(ricoh619->dev, + RICOH619_INT_IR_RTC, reg_data); + if (ret < 0) + dev_err(ricoh619->dev, "Error in writing reg 0x%02x " + "error: %d\n", RICOH619_INT_IR_RTC, ret); + + } } ricoh619->irq_base = irq_base; @@ -512,7 +542,7 @@ int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq, } ret = request_threaded_irq(irq, NULL, ricoh619_irq, - IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED|IRQF_ONESHOT, + IRQ_TYPE_LEVEL_LOW|IRQF_DISABLED|IRQF_ONESHOT, "ricoh619", ricoh619); if (ret < 0) dev_err(ricoh619->dev, "Error in registering interrupt " diff --git a/drivers/power/ricoh619-battery.c b/drivers/power/ricoh619-battery.c index 2a01c4fd89e1..ecab67ffe238 100644 --- a/drivers/power/ricoh619-battery.c +++ b/drivers/power/ricoh619-battery.c @@ -45,6 +45,7 @@ #define ENABLE_FACTORY_MODE #define DISABLE_CHARGER_TIMER /* #define ENABLE_FG_KEEP_ON_MODE */ +#define ENABLE_OCV_TABLE_CALIB @@ -71,12 +72,14 @@ enum int_type { #define RICOH619_CHARGE_RESUME_TIME 1 #define RICOH619_CHARGE_CALC_TIME 1 #define RICOH619_JEITA_UPDATE_TIME 60 +#define RICOH619_DELAY_TIME 60 /* define for FG parameter */ #define RICOH619_MAX_RESET_SOC_DIFF 5 #define RICOH619_GET_CHARGE_NUM 10 #define RICOH619_UPDATE_COUNT_DISP 4 #define RICOH619_UPDATE_COUNT_FULL 4 #define RICOH619_CHARGE_UPDATE_TIME 3 +#define RICOH619_FULL_WAIT_TIME 2 #define RE_CAP_GO_DOWN 10 /* 40 */ #define RICOH619_ENTER_LOW_VOL 70 #define RICOH619_TAH_SEL2 5 @@ -101,6 +104,7 @@ enum { struct ricoh619_soca_info { int Rbat; int n_cap; + int ocv_table_def[11]; int ocv_table[11]; int soc; /* Latest FG SOC value */ int displayed_soc; @@ -117,6 +121,7 @@ struct ricoh619_soca_info { int reset_flg_90; int reset_flg_95; int f_chg_margin; + int chg_cmp_times; int dischg_state; int Vbat[RICOH619_GET_CHARGE_NUM]; int Vsys[RICOH619_GET_CHARGE_NUM]; @@ -135,6 +140,8 @@ struct ricoh619_soca_info { int target_vsys; int target_ibat; int jt_limit; + int OCV100_min; + int OCV100_max; }; struct ricoh619_battery_info { @@ -211,8 +218,9 @@ int g_fg_on_mode; extern int dwc_vbus_status(void); /*This is for full state*/ int g_full_flag; -static int BatteryTableFlageDef=0; +static int BatteryTableFlagDef=0; static int BatteryTypeDef=0; +static void ricoh619_scaling_OCV_table(struct ricoh619_battery_info *info, int cutoff_vol, int full_vol, int *start_per, int *end_per); static int Battery_Type(void) { return BatteryTypeDef; @@ -220,7 +228,7 @@ static int Battery_Type(void) static int Battery_Table(void) { - return BatteryTableFlageDef; + return BatteryTableFlagDef; } static void ricoh619_battery_work(struct work_struct *work) @@ -238,18 +246,20 @@ static void ricoh619_battery_work(struct work_struct *work) static int measure_vbatt_FG(struct ricoh619_battery_info *info, int *data); static int measure_Ibatt_FG(struct ricoh619_battery_info *info, int *data); static int calc_capacity(struct ricoh619_battery_info *info); +static int calc_capacity_2(struct ricoh619_battery_info *info); static int get_OCV_init_Data(struct ricoh619_battery_info *info, int index); static int get_OCV_voltage(struct ricoh619_battery_info *info, int index); static int get_check_fuel_gauge_reg(struct ricoh619_battery_info *info, int Reg_h, int Reg_l, int enable_bit); static int calc_capacity_in_period(struct ricoh619_battery_info *info, - int *cc_cap, bool *is_charging); + int *cc_cap, bool *is_charging, bool cc_rst); static int get_charge_priority(struct ricoh619_battery_info *info, bool *data); static int set_charge_priority(struct ricoh619_battery_info *info, bool *data); static int get_power_supply_status(struct ricoh619_battery_info *info); static int measure_vsys_ADC(struct ricoh619_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 ricoh619_battery_info *info); +static int get_battery_temp_2(struct ricoh619_battery_info *info); static int check_jeita_status(struct ricoh619_battery_info *info, bool *is_jeita_updated); static int calc_ocv(struct ricoh619_battery_info *info) @@ -291,7 +301,7 @@ static int check_charge_status_2(struct ricoh619_battery_info *info, int display } if (info->soca->Ibat_ave < 0) { if (g_full_flag == 1) { - if ((calc_ocv(info) < (get_OCV_voltage(info, 10) - info->soca->f_chg_margin) ) + if ((calc_ocv(info) < (get_OCV_voltage(info, 9) + (get_OCV_voltage(info, 10) - get_OCV_voltage(info, 9))*3/10) ) && (info->soca->soc/100 <= 98) ) { g_full_flag = 0; info->soca->displayed_soc = 100*100; @@ -315,9 +325,12 @@ static int check_charge_status_2(struct ricoh619_battery_info *info, int display * @is_charging: Flag of charging current direction * TRUE : charging (plus) * FALSE: discharging (minus) +* @cc_rst: reset CC_SUM or not +* TRUE : reset +* FALSE: not reset **/ static int calc_capacity_in_period(struct ricoh619_battery_info *info, - int *cc_cap, bool *is_charging) + int *cc_cap, bool *is_charging, bool cc_rst) { int err; uint8_t cc_sum_reg[4]; @@ -380,11 +393,13 @@ static int calc_capacity_in_period(struct ricoh619_battery_info *info, if (err < 0) goto out; - /* CC_SUM <- 0 */ - err = ricoh619_bulk_writes(info->dev->parent, - CC_SUMREG3_REG, 4, cc_clr); - if (err < 0) - goto out; + if (cc_rst == true) { + /* CC_SUM <- 0 */ + err = ricoh619_bulk_writes(info->dev->parent, + CC_SUMREG3_REG, 4, cc_clr); + if (err < 0) + goto out; + } /* CC_pause exist */ err = ricoh619_write(info->dev->parent, CC_CTRL_REG, 0); @@ -522,6 +537,82 @@ static int get_target_use_cap(struct ricoh619_battery_info *info) return 0; } +#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 ricoh619_battery_info *info, int vbat_ocv) +{ + int ret; + int cutoff_ocv; + int i; + int ocv100_new; + int start_per,end_per; + + RICOH_FG_DBG("PMU: %s\n", __func__); + + if (info->soca->Ibat_ave > RICOH619_REL1_SEL_VALUE) { + RICOH_FG_DBG("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; + } + RICOH_FG_DBG("PMU : %s :max %d min %d current %d\n",__func__,info->soca->OCV100_max,info->soca->OCV100_min,vbat_ocv); + RICOH_FG_DBG("PMU : %s : New OCV 100% = 0x%x\n",__func__,ocv100_new); + + /* FG_En Off */ + ret = ricoh619_clr_bits(info->dev->parent, FG_CTRL_REG, 0x01); + if (ret < 0) { + dev_err("PMU: %s Error in FG_En OFF\n", __func__); + goto err; + } + + info->soca->ready_fg = 0; + + //cutoff_ocv = (battery_init_para[info->num][0]<<8) | (battery_init_para[info->num][1]); + cutoff_ocv = get_OCV_voltage(info, 0); + + info->soca->ocv_table_def[10] = info->soca->OCV100_max; + + ricoh619_scaling_OCV_table(info, cutoff_ocv/1000, ocv100_new/1000, &start_per, &end_per); + + ret = ricoh619_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); + RICOH_FG_DBG("PMU: %s : * %d0%% voltage = %d uV\n", + __func__, i, info->soca->ocv_table[i]); + } + + /* FG_En on & Reset*/ + ret = ricoh619_write(info->dev->parent, FG_CTRL_REG, 0x51); + if (ret < 0) { + dev_err("PMU: %s Error in FG_En On & Reset\n", __func__); + goto err; + } + + RICOH_FG_DBG("PMU: %s Exit \n", __func__); + return 0; +err: + return ret; + +} +#endif static void ricoh619_displayed_work(struct work_struct *work) { @@ -532,11 +623,19 @@ static void ricoh619_displayed_work(struct work_struct *work) int last_soc_round; int last_disp_round; int displayed_soc_temp; + int disp_dec; int cc_cap = 0; bool is_charging = true; int i; 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 ret; + int ocv; + int temp_ocv; struct ricoh619_battery_info *info = container_of(work, struct ricoh619_battery_info, displayed_work.work); @@ -553,13 +652,23 @@ static void ricoh619_displayed_work(struct work_struct *work) is_jeita_updated = false; if ((RICOH619_SOCA_START == info->soca->status) - || (RICOH619_SOCA_STABLE == info->soca->status)) + || (RICOH619_SOCA_STABLE == info->soca->status) + || (RICOH619_SOCA_FULL == info->soca->status)) info->soca->ready_fg = 1; /* judege Full state or Moni Vsys state */ if ((RICOH619_SOCA_DISP == info->soca->status) || (RICOH619_SOCA_STABLE == info->soca->status)) { + /* caluc 95% ocv */ + temp_ocv = get_OCV_voltage(info, 10) - + (get_OCV_voltage(info, 10) - get_OCV_voltage(info, 9))/2; + + if ((POWER_SUPPLY_STATUS_FULL == info->soca->chg_status) + && (calc_ocv(info) > temp_ocv)) { + info->soca->status = RICOH619_SOCA_FULL; + info->soca->update_count = 0; + } /* for issue 1 solution start*/ if(g_full_flag == 1){ info->soca->status = RICOH619_SOCA_FULL; @@ -567,27 +676,34 @@ static void ricoh619_displayed_work(struct work_struct *work) } /* for issue1 solution end */ /* check Full state or not*/ - if (info->soca->Ibat_ave >= 0) { - if ((calc_ocv(info) > (get_OCV_voltage(info, 10) - info->soca->f_chg_margin)) + if (info->soca->Ibat_ave >= -20) { + if ((calc_ocv(info) > (get_OCV_voltage(info, 9) + (get_OCV_voltage(info, 10) - get_OCV_voltage(info, 9))*7/10)) || (info->soca->displayed_soc/100 >= 99)) { g_full_flag = 0; info->soca->status = RICOH619_SOCA_FULL; info->soca->update_count = 0; + } else if ((calc_ocv(info) > (get_OCV_voltage(info, 9))) + && (info->soca->Ibat_ave < 300)) + { + g_full_flag = 0; + info->soca->status = RICOH619_SOCA_FULL; + info->soca->update_count = 0; } } else { /* dis-charging */ if (info->soca->displayed_soc/100 < RICOH619_ENTER_LOW_VOL) { + info->soca->target_use_cap = 0; info->soca->status = RICOH619_SOCA_LOW_VOL; } } } if (RICOH619_SOCA_STABLE == info->soca->status) { - info->soca->soc = calc_capacity(info) * 100; + info->soca->soc = calc_capacity_2(info); soc_round = info->soca->soc / 100; last_soc_round = info->soca->last_soc / 100; - info->soca->soc_delta = soc_round - last_soc_round; + info->soca->soc_delta = info->soca->soc - info->soca->last_soc; //get charge status if (info->soca->chg_status == POWER_SUPPLY_STATUS_CHARGING) { @@ -646,14 +762,13 @@ static void ricoh619_displayed_work(struct work_struct *work) } } - if (info->soca->soc_delta >= -1 && info->soca->soc_delta <= 1) { + if (info->soca->soc_delta >= -100 && info->soca->soc_delta <= 100) { info->soca->displayed_soc = info->soca->soc; } else { info->soca->status = RICOH619_SOCA_DISP; } info->soca->last_soc = info->soca->soc; info->soca->soc_delta = 0; - info->soca->update_count = 0; } else if (RICOH619_SOCA_FULL == info->soca->status) { err = check_jeita_status(info, &is_jeita_updated); if (err < 0) { @@ -661,54 +776,91 @@ static void ricoh619_displayed_work(struct work_struct *work) goto end_flow; } info->soca->soc = calc_capacity(info) * 100; - if (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status) { - if (0 == info->soca->jt_limit) { - g_full_flag = 1; - info->soca->displayed_soc = 100*100; - info->soca->update_count = 0; - } else { - info->soca->update_count = 0; - } - } - if (info->soca->Ibat_ave >= 0) { /* for issue 3 */ + info->soca->last_soc = calc_capacity_2(info); /* for DISP */ + + if (info->soca->Ibat_ave >= -20) { /* charging */ if (0 == info->soca->jt_limit) { if (g_full_flag == 1) { - info->soca->displayed_soc = 100*100; - info->soca->update_count = 0; + /* caluc 95% ocv */ + //temp_ocv = get_OCV_voltage(info, 10) - + // (get_OCV_voltage(info, 10) - get_OCV_voltage(info, 9))/2; + temp_ocv = get_OCV_voltage(info, 9); + info->soca->update_count++; + info->soca->chg_cmp_times = 0; + if (info->soca->update_count >= RICOH619_UPDATE_COUNT_FULL) { + if (calc_ocv(info) < temp_ocv) { + if(info->soca->displayed_soc > info->soca->soc) { + info->soca->displayed_soc = info->soca->displayed_soc - 1; + } else { + info->soca->displayed_soc = info->soca->soc; + } + } else { + info->soca->displayed_soc = 100*100; + } + info->soca->update_count = 0; + } } else { - if (info->soca->displayed_soc/100 < 99) { - info->soca->update_count++; - if (info->soca->update_count - >= RICOH619_UPDATE_COUNT_FULL) { - info->soca->displayed_soc = info->soca->displayed_soc + 100; + if (calc_ocv(info) < (get_OCV_voltage(info, 8))) { /* fail safe*/ + g_full_flag = 0; + info->soca->status = RICOH619_SOCA_DISP; + info->soca->soc_delta = 0; + } else if (POWER_SUPPLY_STATUS_FULL == info->soca->chg_status) { + if(info->soca->chg_cmp_times >= RICOH619_FULL_WAIT_TIME) { + info->soca->displayed_soc = 100*100; info->soca->update_count = 0; + g_full_flag = 1; +#ifdef ENABLE_OCV_TABLE_CALIB + err = calib_ocvTable(info,calc_ocv(info)); + if (err < 0) + dev_err(info->dev, "Calibration OCV Error !!\n"); +#endif + } else { + info->soca->chg_cmp_times++; } } else { - info->soca->displayed_soc = 99 * 100; - info->soca->update_count = 0; + info->soca->chg_cmp_times = 0; + if (info->soca->displayed_soc/100 < 99) { + info->soca->update_count++; + if (info->soca->update_count + >= RICOH619_UPDATE_COUNT_FULL) { + info->soca->displayed_soc = info->soca->displayed_soc + 100; + info->soca->update_count = 0; + } + } else { + info->soca->displayed_soc = 99 * 100; + info->soca->update_count = 0; + } } } } else { info->soca->update_count = 0; } - } - if (info->soca->Ibat_ave < 0) { /* for issue 3 */ - info->soca->update_count = 0; + } else { /* discharging */ if (g_full_flag == 1) { - if ((calc_ocv(info) < (get_OCV_voltage(info, 10) - info->soca->f_chg_margin)) - && (info->soca->soc/100 <= 98)) { /* for issue 2 */ - g_full_flag = 0; - info->soca->displayed_soc = 100*100; - info->soca->status = RICOH619_SOCA_DISP; - info->soca->last_soc = info->soca->soc; - info->soca->soc_delta = 0; - } else { - info->soca->displayed_soc = 100*100; + if (info->soca->Ibat_ave <= -1 * RICOH619_REL1_SEL_VALUE) { + if ((calc_ocv(info) < (get_OCV_voltage(info, 9) + (get_OCV_voltage(info, 10) - get_OCV_voltage(info, 9))*3/10)) + && (info->soca->soc/100 <= 98)) { + g_full_flag = 0; + info->soca->displayed_soc = 100 * 100; + info->soca->status = RICOH619_SOCA_DISP; + info->soca->soc_delta = 0; + } else { + info->soca->displayed_soc = 100 * 100; + } + } else { /* into relaxation state */ + ricoh619_read(info->dev->parent, CHGSTATE_REG, ®_val); + if (reg_val & 0xc0) { + info->soca->displayed_soc = 100 * 100; + } else { + g_full_flag = 0; + info->soca->displayed_soc = 100 * 100; + info->soca->status = RICOH619_SOCA_DISP; + info->soca->soc_delta = 0; + } } } else { g_full_flag = 0; info->soca->status = RICOH619_SOCA_DISP; - info->soca->last_soc = info->soca->soc; info->soca->soc_delta = 0; } } @@ -718,7 +870,6 @@ static void ricoh619_displayed_work(struct work_struct *work) info->soca->status = RICOH619_SOCA_DISP; info->soca->last_soc = info->soca->soc; info->soca->soc_delta = 0; - info->soca->update_count = 0; } else { re_cap = get_check_fuel_gauge_reg(info, RE_CAP_H_REG, RE_CAP_L_REG, 0x7fff); @@ -726,14 +877,16 @@ static void ricoh619_displayed_work(struct work_struct *work) 0x7fff); use_cap = fa_cap - re_cap; - if ((info->soca->target_use_cap == 0) - && (info->soca->hurry_up_flg == 0)) { + if (info->soca->target_use_cap == 0) { info->soca->re_cap_old = re_cap; get_target_use_cap(info); } - - if((use_cap >= info->soca->target_use_cap) - || (info->soca->hurry_up_flg == 1)) { + + if(use_cap >= info->soca->target_use_cap) { + info->soca->displayed_soc = info->soca->displayed_soc - 100; + info->soca->displayed_soc = max(0, info->soca->displayed_soc); + info->soca->re_cap_old = re_cap; + } else if (info->soca->hurry_up_flg == 1) { info->soca->displayed_soc = info->soca->displayed_soc - 100; info->soca->displayed_soc = max(0, info->soca->displayed_soc); info->soca->re_cap_old = re_cap; @@ -744,14 +897,14 @@ static void ricoh619_displayed_work(struct work_struct *work) } if (RICOH619_SOCA_DISP == info->soca->status) { - info->soca->soc = calc_capacity(info) * 100; + info->soca->soc = calc_capacity_2(info); soc_round = info->soca->soc / 100; last_soc_round = info->soca->last_soc / 100; last_disp_round = (info->soca->displayed_soc + 50) / 100; info->soca->soc_delta = - info->soca->soc_delta + (soc_round - last_soc_round); + info->soca->soc_delta + (info->soca->soc - info->soca->last_soc); info->soca->last_soc = info->soca->soc; /* six case */ @@ -759,20 +912,24 @@ static void ricoh619_displayed_work(struct work_struct *work) /* if SOC == DISPLAY move to stable */ info->soca->displayed_soc = info->soca->soc ; info->soca->status = RICOH619_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)) { + (POWER_SUPPLY_STATUS_FULL != info->soca->chg_status)) { /* Charge */ if (last_disp_round < soc_round) { /* Case 1 : Charge, Display < SOC */ - info->soca->update_count++; - if ((info->soca->update_count - >= RICOH619_UPDATE_COUNT_DISP) - || (info->soca->soc_delta == 1)) { + if (info->soca->soc_delta >= 100) { info->soca->displayed_soc - = (last_disp_round + 1)*100; - info->soca->update_count = 0; - info->soca->soc_delta = 0; + = 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/100 >= soc_round) { @@ -780,14 +937,13 @@ static void ricoh619_displayed_work(struct work_struct *work) = info->soca->soc ; info->soca->status = RICOH619_SOCA_STABLE; + delay_flag = 1; } } else if (last_disp_round > soc_round) { /* Case 2 : Charge, Display > SOC */ - info->soca->update_count = 0; - if (info->soca->soc_delta >= 3) { - info->soca->displayed_soc = - (last_disp_round + 1)*100; - info->soca->soc_delta -= 3; + if (info->soca->soc_delta >= 300) { + info->soca->displayed_soc += 100; + info->soca->soc_delta -= 300; } if (info->soca->displayed_soc/100 <= soc_round) { @@ -795,24 +951,27 @@ static void ricoh619_displayed_work(struct work_struct *work) = info->soca->soc ; info->soca->status = RICOH619_SOCA_STABLE; + delay_flag = 1; } } } else { - info->soca->update_count = 0; info->soca->soc_delta = 0; } } else { /* Dis-Charge */ if (last_disp_round > soc_round) { /* Case 3 : Dis-Charge, Display > SOC */ - info->soca->update_count++; - if ((info->soca->update_count - >= RICOH619_UPDATE_COUNT_DISP) - || (info->soca->soc_delta == -1)) { + if (info->soca->soc_delta <= -100) { info->soca->displayed_soc - = (last_disp_round - 1)*100; - info->soca->update_count = 0; - info->soca->soc_delta = 0; + = 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/100 <= soc_round) { @@ -820,14 +979,13 @@ static void ricoh619_displayed_work(struct work_struct *work) = info->soca->soc ; info->soca->status = RICOH619_SOCA_STABLE; + delay_flag = 1; } } else if (last_disp_round < soc_round) { /* Case 4 : Dis-Charge, Display < SOC */ - info->soca->update_count = 0; - if (info->soca->soc_delta <= -3) { - info->soca->displayed_soc - = (last_disp_round - 1)*100; - info->soca->soc_delta += 3; + if (info->soca->soc_delta <= -300) { + info->soca->displayed_soc -= 100; + info->soca->soc_delta += 300; } if (info->soca->displayed_soc/100 >= soc_round) { @@ -835,12 +993,41 @@ static void ricoh619_displayed_work(struct work_struct *work) = info->soca->soc ; info->soca->status = RICOH619_SOCA_STABLE; + delay_flag = 1; } } } } else if (RICOH619_SOCA_UNSTABLE == info->soca->status) { + err = ricoh619_read(info->dev->parent, PSWR_REG, &val); + val &= 0x7f; + info->soca->soc = val * 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, + &is_charging, false); + 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(10000, displayed_soc_temp); + displayed_soc_temp = max(0, displayed_soc_temp); + if (0 == info->soca->jt_limit) { - check_charge_status_2(info, info->soca->displayed_soc); + check_charge_status_2(info, displayed_soc_temp); + } else { + info->soca->displayed_soc = displayed_soc_temp; } } else if (RICOH619_SOCA_FG_RESET == info->soca->status) { /* No update */ @@ -852,8 +1039,24 @@ static void ricoh619_displayed_work(struct work_struct *work) } err = ricoh619_read(info->dev->parent, PSWR_REG, &val); val &= 0x7f; + ////debug for Zero state/// + ret = measure_vbatt_FG(info, &Vbat); + ret = measure_Ibatt_FG(info, &Ibat); + ocv = Vbat - Ibat * info->soca->Rbat; + RICOH_FG_DBG("Check ZERO state : Vbat %d, Ibat %d, ocv %d Rbat %d %d\n",Vbat,Ibat,ocv,info->soca->Rbat); + info->soca->soc = calc_capacity(info) * 100; + RICOH_FG_DBG("Check ZERO state : first_pwon %d, RSOC is %d OCV is %d\n",info->first_pwon,info->soca->soc/100,calc_ocv(info)); + RICOH_FG_DBG("Check ZERO state : g_fg_on_mode %d, get ocv voltage %d\n",g_fg_on_mode,get_OCV_voltage(info, 0)); + /////////////////////////// if (info->first_pwon) { info->soca->soc = calc_capacity(info) * 100; + val = (info->soca->soc + 50)/100; + val &= 0x7f; + err = ricoh619_write(info->dev->parent, PSWR_REG, val); + if (err < 0) + dev_err(info->dev, "Error in writing PSWR_REG\n"); + g_soc = val; + if ((info->soca->soc == 0) && (calc_ocv(info) < get_OCV_voltage(info, 0))) { info->soca->displayed_soc = 0; @@ -878,6 +1081,7 @@ static void ricoh619_displayed_work(struct work_struct *work) } else { info->soca->displayed_soc = info->soca->soc; } + info->soca->last_soc = info->soca->soc; info->soca->status = RICOH619_SOCA_STABLE; } } else { @@ -890,7 +1094,7 @@ static void ricoh619_displayed_work(struct work_struct *work) } err = calc_capacity_in_period(info, &cc_cap, - &is_charging); + &is_charging, false); if (err < 0) dev_err(info->dev, "Read cc_sum Error !!-----\n"); @@ -912,6 +1116,7 @@ static void ricoh619_displayed_work(struct work_struct *work) } else { info->soca->displayed_soc = displayed_soc_temp; } + info->soca->last_soc = calc_capacity(info) * 100; info->soca->status = RICOH619_SOCA_UNSTABLE; } } @@ -921,6 +1126,7 @@ static void ricoh619_displayed_work(struct work_struct *work) FG_CTRL_REG, 0x51); if (err < 0) dev_err(info->dev, "Error in writing the control register\n"); + info->soca->last_soc = calc_capacity_2(info); info->soca->status = RICOH619_SOCA_STABLE; info->soca->ready_fg = 0; } @@ -933,9 +1139,9 @@ end_flow: if (err < 0) dev_err(info->dev, "Error in writing PSWR_REG\n"); g_soc = 0x7F; - } else { - if (info->soca->displayed_soc < 0) { - val = 0; + } else if (RICOH619_SOCA_UNSTABLE != info->soca->status) { + if (info->soca->displayed_soc <= 0) { + val = 1; } else { val = (info->soca->displayed_soc + 50)/100; val &= 0x7f; @@ -946,7 +1152,8 @@ end_flow: g_soc = val; - err = calc_capacity_in_period(info, &cc_cap, &is_charging); + err = calc_capacity_in_period(info, &cc_cap, + &is_charging, true); if (err < 0) dev_err(info->dev, "Read cc_sum Error !!-----\n"); } @@ -985,6 +1192,9 @@ end_flow: if (0 == info->soca->ready_fg) queue_delayed_work(info->monitor_wqueue, &info->displayed_work, RICOH619_FG_RESET_TIME * HZ); + else if (delay_flag == 1) + queue_delayed_work(info->monitor_wqueue, &info->displayed_work, + RICOH619_DELAY_TIME * HZ); else if (RICOH619_SOCA_DISP == info->soca->status) queue_delayed_work(info->monitor_wqueue, &info->displayed_work, RICOH619_DISPLAY_UPDATE_TIME * HZ); @@ -1112,7 +1322,6 @@ adjust: info->soca->last_soc = info->soca->soc; info->soca->status = RICOH619_SOCA_DISP; info->soca->soc_delta = 0; - info->soca->update_count = 0; } mutex_unlock(&info->lock); @@ -1299,7 +1508,7 @@ static int ricoh619_init_fgsoca(struct ricoh619_battery_info *info) info->soca->n_cap = get_OCV_init_Data(info, 11); info->soca->f_chg_margin = (get_OCV_voltage(info, 10) - - get_OCV_voltage(info, 9)) / 10 * 3; + get_OCV_voltage(info, 9)) / 10; info->soca->displayed_soc = 0; info->soca->suspend_soc = 0; @@ -1309,6 +1518,7 @@ static int ricoh619_init_fgsoca(struct ricoh619_battery_info *info) info->soca->status = RICOH619_SOCA_START; /* stable count down 11->2, 1: reset; 0: Finished; */ info->soca->stable_count = 11; + info->soca->chg_cmp_times = 0; info->soca->dischg_state = 0; info->soca->Vbat_ave = 0; info->soca->Vsys_ave = 0; @@ -1325,6 +1535,8 @@ static int ricoh619_init_fgsoca(struct ricoh619_battery_info *info) info->soca->Ibat[i] = 0; } + g_full_flag = 0; + #ifdef ENABLE_FG_KEEP_ON_MODE g_fg_on_mode = 1; #else @@ -1420,7 +1632,7 @@ static int check_jeita_status(struct ricoh619_battery_info *info, bool *is_jeita /* Check FG Reset */ if (info->soca->ready_fg) { - temp = get_battery_temp(info) / 10; + temp = get_battery_temp_2(info) / 10; } else { RICOH_FG_DBG(KERN_INFO "JEITA: %s *** cannot update by resetting FG ******\n", __func__); goto out; @@ -1700,95 +1912,133 @@ static int Calc_Linear_Interpolation(int x0, int y0, int x1, int y1, int y) return x; } +static void ricoh619_scaling_OCV_table(struct ricoh619_battery_info *info, int cutoff_vol, int full_vol, int *start_per, int *end_per) +{ + int ret = 0; + int i, j; + int temp; + int percent_step; + int OCV_percent_new[11]; + + /* get ocv table. this table is calculated by Apprication */ + //RICOH_FG_DBG("PMU : %s : original table\n",__func__); + for (i = 0; i <= 10; i = i+1) { + RICOH_FG_DBG(KERN_INFO "PMU: %s : %d0%% voltage = %d uV\n", + __func__, i, info->soca->ocv_table_def[i]); + } + //RICOH_FG_DBG("PMU: %s : cutoff_vol %d full_vol %d\n", + // __func__, cutoff_vol,full_vol); + + /* Check Start % */ + 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)); + i = 11; + } + } + + /* 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)); + i = 11; + } + } + + /* calc new ocv percent */ + percent_step = ( *end_per - *start_per) / 10; + //RICOH_FG_DBG("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; + + j = 11; + } + } + } + RICOH_FG_DBG("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; + RICOH_FG_DBG("PMU : %s : ocv_table %d is %d v\n",__func__, i, temp); + } + +} + static int ricoh619_set_OCV_table(struct ricoh619_battery_info *info) { int ret = 0; - int ocv_table[11]; + int OCV_set_table[11]; int i, j; + int full_ocv; int available_cap; + int available_cap_ori; + int OCV_100_def; + int OCV_0_def; + int OCV_100_diff; + int OCV_0_diff; int temp; - int start_par; + int start_per; + int end_per; int percent_step; int OCV_percent_new[11]; 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); + RICOH_FG_DBG(KERN_INFO "PMU: %s : %d0%% voltage = %d uV\n", + __func__, i, info->soca->ocv_table_def[i]); + } info->soca->target_vsys = info->fg_target_vsys; info->soca->target_ibat = info->fg_target_ibat; //for debug - RICOH_FG_DBG("PMU : %s : target_vsys is %d target_ibat is %d",__func__,info->soca->target_vsys,info->soca->target_ibat); + RICOH_FG_DBG("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. */ - /* get ocv table. this table is calculated by Apprication */ - 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; - ocv_table[i] = temp; - - } - - /* get internal impedence */ temp = (battery_init_para[info->num][24]<<8) | (battery_init_para[info->num][25]); Rbat = temp * 1000 / 512 * 5000 / 4095; Ibat_min = -1 * info->soca->target_ibat; info->soca->Rsys = Rbat + 55; 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; - - RICOH_FG_DBG("PMU: ------- Rbat= %d: Rsys= %d: cutoff_ocv= %d: =======\n", - Rbat, info->soca->Rsys, info->soca->cutoff_ocv); - - /* Check Start % */ - for (i = 1; i < 11; i++) { - if (ocv_table[i] >= info->soca->cutoff_ocv * 10) { - /* unit is 0.001% */ - start_par = Calc_Linear_Interpolation( - (i-1)*1000, ocv_table[i-1], i*1000, - ocv_table[i], (info->soca->cutoff_ocv * 10)); - i = 11; - } - } - /* calc new ocv percent */ - percent_step = (10000 - start_par) / 10; - - for (i = 0; i < 11; i++) { - OCV_percent_new[i] - = start_par + percent_step*(i - 0); - } - - /* calc new ocv voltage */ - for (i = 0; i < 11; i++) { - for (j = 1; j < 11; j++) { - if (1000*j >= OCV_percent_new[i]) { - temp = Calc_Linear_Interpolation( - ocv_table[j-1], (j-1)*1000, - ocv_table[j] , j*1000, - OCV_percent_new[i]); - - temp = temp * 4095 / 50000; - - battery_init_para[info->num][i*2 + 1] = temp; - battery_init_para[info->num][i*2] = temp >> 8; - - j = 11; - } - } - } - - 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; - RICOH_FG_DBG("PMU: ------- ocv_table[%d]= %d: =======\n", - i, temp); - } - + ricoh619_scaling_OCV_table(info, info->soca->cutoff_ocv, full_ocv, &start_per, &end_per); /* calc available capacity */ /* get avilable capacity */ @@ -1797,21 +2047,155 @@ static int ricoh619_set_OCV_table(struct ricoh619_battery_info *info) | (battery_init_para[info->num][23]); available_cap = available_cap - * ((10000 - start_par) / 100) / 100 ; + * ((10000 - start_per) / 100) / 100 ; battery_init_para[info->num][23] = available_cap; battery_init_para[info->num][22] = available_cap >> 8; } - ret = ricoh619_bulk_writes_bank1(info->dev->parent, - BAT_INIT_TOP_REG, 32, battery_init_para[info->num]); + ret = ricoh619_clr_bits(info->dev->parent, FG_CTRL_REG, 0x01); if (ret < 0) { + dev_err(info->dev, "error in FG_En off\n"); + goto err; + } + //////////////////////////////// + //////////////////////////////// + //check OCV calibration or not + /* get ocv table from setting */ + for (i = 0; i < 11; i++){ + ret = ricoh619_read_bank1(info->dev->parent, (0xBC + i*2), &val); + if (ret < 0) { dev_err(info->dev, "batterry initialize error\n"); return ret; + } + ret = ricoh619_read_bank1(info->dev->parent, (0xBD + i*2), &val2); + if (ret < 0) { + dev_err(info->dev, "batterry initialize error\n"); + return ret; + } + val &= 0x0F; + OCV_set_table[i] = val2 + (val << 8); + RICOH_FG_DBG("PMU : %s : no %d OCV_set_table %x\n", __func__, i, OCV_set_table[i]); + } - return 1; + OCV_100_def = (battery_init_para[info->num][20]<<8) + | (battery_init_para[info->num][21]); + + OCV_0_def = (battery_init_para[info->num][0]<<8) + | (battery_init_para[info->num][1]); + + if(OCV_100_def < OCV_set_table[10]) { + OCV_100_diff = OCV_set_table[10] - OCV_100_def; + } else { + OCV_100_diff = OCV_100_def - OCV_set_table[10]; + } + + if(OCV_0_def < OCV_set_table[0]) { + OCV_0_diff = OCV_set_table[0] - OCV_0_def; + } else { + OCV_0_diff = OCV_0_def - OCV_set_table[0]; + } + RICOH_FG_DBG("PMU : %s : def OCV 100 %x OCV 0 %x \n", __func__, OCV_100_def, OCV_0_def); + RICOH_FG_DBG("PMU : %s : OCV 100 %x OCV 0 %x \n", __func__, OCV_set_table[10], OCV_set_table[0]); + RICOH_FG_DBG("PMU : %s : diff OCV 100 %x OCV 0 %x \n", __func__, OCV_100_diff, OCV_0_diff); + + if ( (OCV_100_diff > 5) + &&(OCV_0_diff < 5)) + {/* keep setting OCV table */ + for (i = 0; i < 11; i++) { + RICOH_FG_DBG("PMU : 1\n"); + battery_init_para[info->num][i*2+1] = OCV_set_table[i]; + battery_init_para[info->num][i*2] = OCV_set_table[i] >> 8; + } + } + + ///////////////////////////////// + ret = ricoh619_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 = ricoh619_write_bank1(info->dev->parent, 0xDC, val); + if (ret < 0) { + dev_err(info->dev, "batterry initialize error\n"); + goto err; + } + + ret = ricoh619_read_bank1(info->dev->parent, 0xDC, &val2); + if (ret < 0) { + dev_err(info->dev, "batterry initialize error\n"); + goto err; + } + + ret = ricoh619_write_bank1(info->dev->parent, 0xDC, val_temp); + if (ret < 0) { + dev_err(info->dev, "batterry initialize error\n"); + goto err; + } + + RICOH_FG_DBG("PMU : %s : original 0x%x, before 0x%x, after 0x%x\n",__func__, val_temp, val, val2); + + if (val != val2) { + ret = ricoh619_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 = ricoh619_read_bank1(info->dev->parent, 0xD2, &val); + if (ret < 0) { + dev_err(info->dev, "batterry initialize error\n"); + goto err; + } + + ret = ricoh619_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 = ricoh619_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 = ricoh619_write_bank1(info->dev->parent, 0xD4+i, battery_init_para[info->num][23+i]); + if (ret < 0) { + dev_err(info->dev, "batterry initialize error\n"); + return ret; + } + } + } else { + ret = ricoh619_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 */ @@ -1854,15 +2238,22 @@ static int ricoh619_init_battery(struct ricoh619_battery_info *info) return ret; } - ret = ricoh619_read(info->dev->parent, FG_CTRL_REG, &val); +// ret = ricoh619_read(info->dev->parent, FG_CTRL_REG, &val); +// if (ret < 0) { +// dev_err(info->dev, "Error in reading the control register\n"); +// return ret; +// } + +// val = (val & 0x10) >> 4; +// info->first_pwon = (val == 0) ? 1 : 0; + ret = ricoh619_read(info->dev->parent, PSWR_REG, &val); if (ret < 0) { - dev_err(info->dev, "Error in reading the control register\n"); + dev_err(info->dev,"Error in reading PSWR_REG %d\n", ret); return ret; } - - val = (val & 0x10) >> 4; info->first_pwon = (val == 0) ? 1 : 0; - + g_soc = val & 0x7f; + ret = ricoh619_set_OCV_table(info); if (ret < 0) { dev_err(info->dev, "Error in writing the OCV Tabler\n"); @@ -1895,10 +2286,15 @@ static int ricoh619_init_battery(struct ricoh619_battery_info *info) static int ricoh619_init_charger(struct ricoh619_battery_info *info) { int err; + int i; 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; @@ -2151,6 +2547,41 @@ static int ricoh619_init_charger(struct ricoh619_battery_info *info) 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 = ricoh619_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; + } + RICOH_FG_DBG("PMU : %s : test test val %d, val2 %d vfchg %d\n", __func__, val, val2, vfchg_val); + + /* get value */ + err = ricoh619_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; + RICOH_FG_DBG("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; + + RICOH_FG_DBG("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 */ @@ -2161,8 +2592,9 @@ static int ricoh619_init_charger(struct ricoh619_battery_info *info) ricoh619_write(info->dev->parent, RICOH619_ADC_CNT2, 0x0); /* Enable VSYS pin conversion in auto-ADC */ ricoh619_write(info->dev->parent, RICOH619_ADC_CNT1, 0x10); - /* Set VSYS threshold low voltage = 3.50v */ - ricoh619_write(info->dev->parent, RICOH619_ADC_VSYS_THL, 0x77); + /* Set VSYS threshold low voltage value = (voltage(V)*255)/(3*2.5) */ + val = info->alarm_vol_mv * 255 / 7500; + ricoh619_write(info->dev->parent, RICOH619_ADC_VSYS_THL, val); /* Start auto-mode & average 4-time conversion mode for ADC */ ricoh619_write(info->dev->parent, RICOH619_ADC_CNT3, 0x28); /* Enable master ADC INT */ @@ -2572,7 +3004,7 @@ static int calc_capacity(struct ricoh619_battery_info *info) int nt; int temperature; - temperature = get_battery_temp(info) / 10; /* unit 0.1 degree -> 1 degree */ + temperature = get_battery_temp_2(info) / 10; /* unit 0.1 degree -> 1 degree */ if (temperature >= 25) { nt = 0; @@ -2594,6 +3026,50 @@ static int calc_capacity(struct ricoh619_battery_info *info) return temp; /* Unit is 1% */ } +static int calc_capacity_2(struct ricoh619_battery_info *info) +{ + uint8_t val; + long capacity; + int re_cap, fa_cap; + int temp; + int ret = 0; + int nt; + int temperature; + + 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) * RICOH619_TAH_SEL2 * 625 / 100; + } else { + nt = (625 + (5 - temperature) * RICOH619_TAL_SEL2 * 625 / 100); + } + + 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) + 50; + capacity = min(10000, capacity); + capacity = max(0, capacity); + } else { + ret = ricoh619_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; + } + + + temp = (int)(capacity * 100 * 100 / (10000 - nt)); + + return temp; /* Unit is 0.01% */ +} + static int get_battery_temp(struct ricoh619_battery_info *info) { int ret = 0; @@ -2624,6 +3100,141 @@ static int get_battery_temp(struct ricoh619_battery_info *info) return ret; } +static int get_battery_temp_2(struct ricoh619_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 = ricoh619_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 = ricoh619_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 { + RICOH_FG_DBG("PMU %s Skip to compensate temperature\n", __func__); + 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 { + RICOH_FG_DBG("PMU %s Skip to compensate temperature\n", __func__); + 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); + RICOH_FG_DBG("PMU %s low temperature %d\n", __func__, new_temp/10); + } else if (temp > 520000) { + /* High Temperature */ + if (0 != (2500 - Vthm)) { + Rthm = 100 * 10 * (Vthm - Vsns) / (2500 - Vthm); + } else { + RICOH_FG_DBG("PMU %s Skip to compensate temperature\n", __func__); + goto out; + } + RICOH_FG_DBG("PMU %s [Rthm] Rthm %d[ohm]\n", __func__, Rthm); + + 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); + RICOH_FG_DBG("PMU %s high temperature %d\n", __func__, new_temp/10); + } 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 ricoh619_battery_info *info) { int ret = 0; @@ -2830,6 +3441,7 @@ static int ricoh619_batt_get_prop(struct power_supply *psy, mutex_lock(&info->lock); switch (psp) { +#if 0 case POWER_SUPPLY_PROP_ONLINE: ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status); if (ret < 0) { @@ -2842,6 +3454,7 @@ static int ricoh619_batt_get_prop(struct power_supply *psy, else if (psy->type == POWER_SUPPLY_TYPE_USB) val->intval = (status & 0x80 ? 1 : 0); break; +#endif /* this setting is same as battery driver of 584 */ case POWER_SUPPLY_PROP_STATUS: ret = get_power_supply_status(info); @@ -2899,7 +3512,7 @@ static int ricoh619_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_TEMP: if (info->soca->ready_fg) { ret = 0; - val->intval = get_battery_temp(info); + val->intval = get_battery_temp_2(info); info->battery_temp = val->intval/10; RICOH_FG_DBG( "battery temperature is %d degree\n", info->battery_temp); } else { @@ -3002,8 +3615,8 @@ static __devinit int ricoh619_battery_probe(struct platform_device *pdev) int type_n; int ret, temp; - RICOH_FG_DBG("PMU: %s\n", __func__); - + RICOH_FG_DBG("PMU:2013.8.3 %s\n", __func__); + info = kzalloc(sizeof(struct ricoh619_battery_info), GFP_KERNEL); if (!info) return -ENOMEM; @@ -3207,9 +3820,10 @@ static int __devexit ricoh619_battery_remove(struct platform_device *pdev) if (err < 0) dev_err(info->dev, "Error in writing PSWR_REG\n"); g_soc = 0x7f; - } else { - if (info->soca->displayed_soc < 0) { - val = 0; + } else if (info->soca->status != RICOH619_SOCA_START + && info->soca->status != RICOH619_SOCA_UNSTABLE) { + if (info->soca->displayed_soc <= 0) { + val = 1; } else { val = (info->soca->displayed_soc + 50)/100; val &= 0x7f; @@ -3220,7 +3834,8 @@ static int __devexit ricoh619_battery_remove(struct platform_device *pdev) g_soc = val; - ret = calc_capacity_in_period(info, &cc_cap, &is_charging); + ret = calc_capacity_in_period(info, &cc_cap, + &is_charging, true); if (ret < 0) dev_err(info->dev, "Read cc_sum Error !!-----\n"); } @@ -3294,10 +3909,11 @@ static int ricoh619_battery_suspend(struct device *dev) if (err < 0) dev_err(info->dev, "Error in writing PSWR_REG\n"); g_soc = 0x7F; - info->soca->suspend_soc = (info->soca->displayed_soc + 50)/100; - } else { - if (info->soca->displayed_soc < 0) { - val = 0; + info->soca->suspend_soc = info->soca->displayed_soc; + } else if (info->soca->status != RICOH619_SOCA_START + && info->soca->status != RICOH619_SOCA_UNSTABLE) { + if (info->soca->displayed_soc <= 0) { + val = 1; } else { val = (info->soca->displayed_soc + 50)/100; val &= 0x7f; @@ -3308,17 +3924,37 @@ static int ricoh619_battery_suspend(struct device *dev) g_soc = val; - info->soca->suspend_soc = (info->soca->displayed_soc + 50)/100; + info->soca->suspend_soc = info->soca->displayed_soc; - ret = calc_capacity_in_period(info, &cc_cap, &is_charging); + ret = calc_capacity_in_period(info, &cc_cap, + &is_charging, true); if (ret < 0) dev_err(info->dev, "Read cc_sum Error !!-----\n"); + } else if (info->soca->status == RICOH619_SOCA_START + || info->soca->status == RICOH619_SOCA_UNSTABLE) { + + ret = ricoh619_read(info->dev->parent, PSWR_REG, &val); + if (ret < 0) + dev_err(info->dev, "Error in reading the pswr register\n"); + val &= 0x7f; + + info->soca->suspend_soc = val * 100; + } + + if (info->soca->status == RICOH619_SOCA_DISP + || info->soca->status == RICOH619_SOCA_STABLE + || info->soca->status == RICOH619_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 == RICOH619_SOCA_STABLE || info->soca->status == RICOH619_SOCA_FULL) info->soca->status = RICOH619_SOCA_DISP; - /* set rapid timer 300 min */ err = ricoh619_set_bits(info->dev->parent, TIMSET_REG, 0x03); if (err < 0) { @@ -3385,7 +4021,7 @@ static int ricoh619_battery_resume(struct device *dev) } ret = calc_capacity_in_period(info, &cc_cap, - &is_charging); + &is_charging, true); if (ret < 0) dev_err(info->dev, "Read cc_sum Error !!-----\n"); @@ -3410,9 +4046,17 @@ static int ricoh619_battery_resume(struct device *dev) } else info->soca->displayed_soc = 0; } else { - info->soca->soc = info->soca->suspend_soc * 100; + info->soca->soc = info->soca->suspend_soc; + + if (RICOH619_SOCA_START == info->soca->status + || RICOH619_SOCA_UNSTABLE == info->soca->status) { + ret = calc_capacity_in_period(info, &cc_cap, + &is_charging, false); + } else { + ret = calc_capacity_in_period(info, &cc_cap, + &is_charging, true); + } - ret = calc_capacity_in_period(info, &cc_cap, &is_charging); if (ret < 0) dev_err(info->dev, "Read cc_sum Error !!-----\n"); @@ -3431,8 +4075,7 @@ static int ricoh619_battery_resume(struct device *dev) } if (RICOH619_SOCA_DISP == info->soca->status) { - info->soca->last_soc = calc_capacity(info) * 100; - info->soca->soc_delta = 0; + info->soca->last_soc = calc_capacity_2(info); } } info->soca->update_count = 0; @@ -3476,7 +4119,7 @@ static int ricoh619_battery_resume(struct device *dev) RICOH619_JEITA_UPDATE_TIME * HZ); } } - ricoh619_write(info->dev->parent, 0x9d, 0x00); +// ricoh619_write(info->dev->parent, 0x9d, 0x00); // enable_irq(charger_irq + RICOH619_IRQ_FONCHGINT); // enable_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT); // enable_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT); diff --git a/drivers/regulator/ricoh619-regulator.c b/drivers/regulator/ricoh619-regulator.c index 5502d87f1042..900f25ef9eee 100644 --- a/drivers/regulator/ricoh619-regulator.c +++ b/drivers/regulator/ricoh619-regulator.c @@ -285,7 +285,7 @@ static unsigned int ricoh619_dcdc_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; case 2: return REGULATOR_MODE_STANDBY; - case 4: + case 3: return REGULATOR_MODE_NORMAL; default: return -1; diff --git a/drivers/rtc/rtc-ricoh619.c b/drivers/rtc/rtc-ricoh619.c old mode 100644 new mode 100755 index d26d2189daec..1db0367b0141 --- a/drivers/rtc/rtc-ricoh619.c +++ b/drivers/rtc/rtc-ricoh619.c @@ -6,7 +6,7 @@ * Copyright (C) 2012-2013 RICOH COMPANY,LTD * * Based on code - * Copyright (C) 2011 NVIDIA Corporation + * Copyright (C) 2011 NVIDIA Corporation * * this program is free software; you can redistribute it and/or modify * it under the terms of the gnu general public license as published by @@ -19,7 +19,7 @@ * more details. * * you should have received a copy of the gnu general public license - * along with this program. If not, see . + * along with this program. If not, see . * */ @@ -37,10 +37,9 @@ #include struct ricoh619_rtc { - unsigned long epoch_start; int irq; struct rtc_device *rtc; - bool irq_en; + bool irq_en; }; static int ricoh619_read_regs(struct device *dev, int reg, int len, @@ -70,21 +69,24 @@ static int ricoh619_write_regs(struct device *dev, int reg, int len, return ret; } +// 0=OK, -EINVAL= FAIL static int ricoh619_rtc_valid_tm(struct device *dev, struct rtc_time *tm) { - if (tm->tm_year >= (rtc_year_offset + 99) - || tm->tm_mon > 12 + if (tm->tm_year > 199 || tm->tm_year < 70 + || tm->tm_mon > 11 || tm->tm_mon < 0 || tm->tm_mday < 1 - || tm->tm_mday > rtc_month_days(tm->tm_mon, - tm->tm_year + os_ref_year) - || tm->tm_hour >= 24 - || tm->tm_min >= 60 - || tm->tm_sec >= 60) { - dev_err(dev->parent, "\n returning error due to time" - "%d/%d/%d %d:%d:%d", tm->tm_mon, tm->tm_mday, - tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); + || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + os_ref_year) + || tm->tm_hour >= 24 || tm->tm_hour <0 + || tm->tm_min < 0 || tm->tm_min >= 60 + || tm->tm_sec < 0 || tm->tm_sec >= 60 + ) + { + dev_err(dev->parent, "PMU: %s *** Returning error due to time, %d/%d/%d %d:%d:%d *****\n", + __func__, tm->tm_mon, tm->tm_mday, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); + return -EINVAL; } + return 0; } @@ -114,47 +116,199 @@ static void convert_decimal_to_bcd(u8 *buf, u8 len) static void print_time(struct device *dev, struct rtc_time *tm) { - dev_info(dev, "rtc-time : %d/%d/%d %d:%d\n", - (tm->tm_mon + 1), tm->tm_mday, (tm->tm_year + os_ref_year), - tm->tm_hour, tm->tm_min); + dev_info(dev, "PMU: %s *** rtc-time : %d/%d/%d %d:%d:%d *****\n", + __func__, (tm->tm_mon), tm->tm_mday, (tm->tm_year + os_ref_year), tm->tm_hour, tm->tm_min,tm->tm_sec); +} + +static int ricoh619_rtc_periodic_disable(struct device *dev) +{ + int err; + uint8_t reg_data; + + // disable function + err = ricoh619_read_regs(dev, rtc_ctrl1, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error=0x%x\n", err); + return err; + } + reg_data &= 0xf8; + err = ricoh619_write_regs(dev, rtc_ctrl1, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error=0x%x\n", err); + return err; + } + + // clear alarm flag and CTFG + err = ricoh619_read_regs(dev, rtc_ctrl2, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error=0x%x\n", err); + return err; + } + reg_data &= ~0x85;// 1000-0101 + err = ricoh619_write_regs(dev, rtc_ctrl2, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error=0x%x\n", err); + return err; + } + + return 0; +} + +static int ricoh619_rtc_clk_adjust(struct device *dev, uint8_t clk) +{ + return ricoh619_write_regs(dev, rtc_adjust, 1, &clk); +} + +static int ricoh619_rtc_Pon_get_clr(struct device *dev, uint8_t *Pon_f) +{ + int err; + uint8_t reg_data; + + err = ricoh619_read_regs(dev, rtc_ctrl2, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "rtc_ctrl1 read err=0x%x\n", err); + return err; + } +// printk("%s,PON=1 -- CTRL2=0x%x\n", __func__, reg_data); + + if(reg_data & 0x10) + { + *Pon_f = 1; + //clear VDET PON + reg_data &= ~0x5b;// 0101-1011 + reg_data |= 0x20; // 0010-0000 + err = ricoh619_write_regs(dev, rtc_ctrl2, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "rtc_ctrl1 write err=0x%x\n", err); + } + } + else + { + *Pon_f = 0; + } + + + return err; +} + +// 0-12hour, 1-24hour +static int ricoh619_rtc_hour_mode_get(struct device *dev, int *mode) +{ + int err; + + err = ricoh619_read_regs(dev, rtc_ctrl1, 1, mode); + if(err < 0) + dev_err(dev->parent, "read rtc ctrl1 error\n"); + + if(*mode & 0x20) + *mode = 1; + else + *mode = 0; + + return err; +} + +// 0-12hour, 1-24hour +static int ricoh619_rtc_hour_mode_set(struct device *dev, int mode) +{ + uint8_t reg_data; + int err; + + err = ricoh619_read_regs(dev, rtc_ctrl1, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error\n"); + return err; + } + if(mode == 0) + reg_data &= 0xDF; + else + reg_data |= 0x20; + err = ricoh619_write_regs(dev, rtc_ctrl1, 1, ®_data); + if(err < 0) + { + dev_err(dev->parent, "write rtc_ctrl1 error\n"); + } + + return err; } + static int ricoh619_rtc_read_time(struct device *dev, struct rtc_time *tm) { u8 buff[7]; int err; + int cent_flag; + int i; + +// printk(KERN_INFO "PMU: %s\n", __func__); err = ricoh619_read_regs(dev, rtc_seconds_reg, sizeof(buff), buff); + if (err < 0) { - dev_err(dev, "\n %s :: failed to read time\n", __FILE__); + dev_err(dev->parent, "PMU: %s *** failed to read time *****\n", __func__); return err; } - convert_bcd_to_decimal(buff, sizeof(buff)); + + if (buff[5] & 0x80) + cent_flag = 1; + else + cent_flag = 0; + + buff[5] = buff[5]&0x1f; //bit5 19_20 + convert_bcd_to_decimal(buff, sizeof(buff)); + tm->tm_sec = buff[0]; tm->tm_min = buff[1]; - tm->tm_hour = buff[2]; + tm->tm_hour = buff[2]; //bit5 PA_H20 tm->tm_wday = buff[3]; tm->tm_mday = buff[4]; - tm->tm_mon = buff[5] - 1; - tm->tm_year = buff[6] + rtc_year_offset; -// print_time(dev, tm); - return ricoh619_rtc_valid_tm(dev, tm); + tm->tm_mon = buff[5]; //for print + tm->tm_year = buff[6] + 100 * cent_flag; + print_time(dev, tm); //for print + tm->tm_mon = buff[5] - 1; //back to system 0-11 + + return 0; } static int ricoh619_rtc_set_time(struct device *dev, struct rtc_time *tm) { u8 buff[7]; int err; + int cent_flag; + +// printk(KERN_INFO "PMU: %s\n", __func__); + + if(ricoh619_rtc_valid_tm(dev, tm) != 0) + { + return -EINVAL; + } + + if (tm->tm_year >= 100) + cent_flag = 1; + else + cent_flag = 0; -// print_time(dev, tm); + tm->tm_mon = tm->tm_mon + 1; buff[0] = tm->tm_sec; buff[1] = tm->tm_min; buff[2] = tm->tm_hour; buff[3] = tm->tm_wday; buff[4] = tm->tm_mday; - buff[5] = tm->tm_mon + 1; - buff[6] = tm->tm_year - rtc_year_offset; + buff[5] = tm->tm_mon; //system set 0-11 + buff[6] = tm->tm_year - 100 * cent_flag; + print_time(dev, tm); // RTC_TEST convert_decimal_to_bcd(buff, sizeof(buff)); + + if (1 == cent_flag) + buff[5] |= 0x80; + err = ricoh619_write_regs(dev, rtc_seconds_reg, sizeof(buff), buff); if (err < 0) { dev_err(dev->parent, "\n failed to program new time\n"); @@ -163,118 +317,221 @@ static int ricoh619_rtc_set_time(struct device *dev, struct rtc_time *tm) return 0; } -static int ricoh619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm); -static int ricoh619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +static int ricoh619_rtc_alarm_is_enabled(struct device *dev, uint8_t *enabled) { struct ricoh619_rtc *rtc = dev_get_drvdata(dev); - unsigned long seconds; - u8 buff[6]; int err; - struct rtc_time tm; - - if (rtc->irq == -1) - return -EIO; - - rtc_tm_to_time(&alrm->time, &seconds); - err = ricoh619_rtc_read_time(dev, &tm); - if (err) { - dev_err(dev, "\n failed to read time\n"); - return err; + uint8_t reg_data; + + err = 0; + err = ricoh619_read_regs(dev, rtc_ctrl1, 1,®_data); + if(err) + { + dev_err(dev->parent, "read rtc_ctrl1 error 0x%lx\n", err); + *enabled = 0; } - rtc_tm_to_time(&tm, &rtc->epoch_start); - - dev_info(dev->parent, "\n setting alarm to requested time::\n"); -// print_time(dev->parent, &alrm->time); - - if (WARN_ON(alrm->enabled && (seconds < rtc->epoch_start))) { - dev_err(dev->parent, "\n can't set alarm to requested time\n"); - return -EINVAL; + else + { + if(reg_data & 0x40) + *enabled = 1; + else + *enabled = 0; } + return err; +} - if (alrm->enabled && !rtc->irq_en) - rtc->irq_en = true; - else if (!alrm->enabled && rtc->irq_en) - rtc->irq_en = false; - - buff[0] = alrm->time.tm_sec; - buff[1] = alrm->time.tm_min; - buff[2] = alrm->time.tm_hour; - buff[3] = alrm->time.tm_mday; - buff[4] = alrm->time.tm_mon + 1; - buff[5] = alrm->time.tm_year - rtc_year_offset; - convert_decimal_to_bcd(buff, sizeof(buff)); - buff[3] |= 0x80; /* set DAL_EXT */ - err = ricoh619_write_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff); - if (err) { - dev_err(dev->parent, "\n unable to set alarm\n"); - return -EBUSY; +// 0-disable, 1-enable +static int ricoh619_rtc_alarm_enable(struct device *dev, unsigned int enabled) +{ + struct ricoh619_rtc *rtc = dev_get_drvdata(dev); + int err; + uint8_t reg_data; + +// printk(KERN_INFO "PMU: %s :%d\n", __func__,enabled); + + err = 0; + if(enabled) + { + rtc->irq_en = 1; + err = ricoh619_read_regs(dev, rtc_ctrl1, 1,®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error 0x%lx\n", err); + goto ERR; + } + reg_data |= 0x40;// set DALE + err = ricoh619_write_regs(dev, rtc_ctrl1, 1,®_data); + if(dev < 0) + dev_err(dev->parent, "write rtc_ctrl1 error 0x%lx\n", err); } - - err = ricoh619_read_regs(dev, rtc_ctrl2, 1, buff); - if (err) { - dev_err(dev->parent, "unable to read rtc_ctrl2 reg\n"); - return -EBUSY; + else + { + rtc->irq_en = 0; + err = ricoh619_read_regs(dev, rtc_ctrl1, 1,®_data); + if(err < 0) + { + dev_err(dev->parent, "read rtc_ctrl1 error 0x%lx\n", err); + goto ERR; + } + reg_data &= 0xbf;// clear DALE + err = ricoh619_write_regs(dev, rtc_ctrl1, 1,®_data); + if(dev < 0) + dev_err(dev->parent, "write rtc_ctrl1 error 0x%lx\n", err); } - buff[1] = buff[0] & ~0x81; /* to clear alarm-D flag, and set adjustment parameter */ - buff[0] = 0x60; /* to enable alarm_d and 24-hour format */ - err = ricoh619_write_regs(dev, rtc_ctrl1, 2, buff); - if (err) { - dev_err(dev, "failed programming rtc ctrl regs\n"); - return -EBUSY; - } -return err; +ERR: + return err; } static int ricoh619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { u8 buff[6]; + u8 buff_cent; int err; + int cent_flag; + unsigned char enabled_flag; + +// printk(KERN_INFO "PMU: %s\n", __func__); + + err = 0; + + alrm->time.tm_sec = 0; + alrm->time.tm_min = 0; + alrm->time.tm_hour = 0; + alrm->time.tm_mday = 0; + alrm->time.tm_mon = 0; + alrm->time.tm_year = 0; + alrm->enabled = 0; + + err = ricoh619_read_regs(dev, rtc_month_reg, 1, &buff_cent); + if (err < 0) { + dev_err(dev->parent, "PMU: %s *** failed to read time *****\n", __func__); + return err; + } + if (buff_cent & 0x80) + cent_flag = 1; + else + cent_flag = 0; err = ricoh619_read_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff); - if (err) + if(err) + { + dev_err(dev->parent, "RTC: %s *** read rtc_alarm timer error 0x%lx\n", __func__, err); + return err; + } + + err = ricoh619_read_regs(dev, rtc_ctrl1, 1,&enabled_flag); + if(err) + { + dev_err(dev->parent, "RTC: %s *** read rtc_enable flag error 0x%lx\n", __func__, err); return err; + } + if(enabled_flag & 0x40) + enabled_flag = 1; + else + enabled_flag = 0; + buff[3] &= ~0x80; /* clear DAL_EXT */ - convert_bcd_to_decimal(buff, sizeof(buff)); + buff[3] = buff[3]&0x3f; + convert_bcd_to_decimal(buff, sizeof(buff)); + alrm->time.tm_sec = buff[0]; alrm->time.tm_min = buff[1]; alrm->time.tm_hour = buff[2]; alrm->time.tm_mday = buff[3]; + alrm->time.tm_mon = buff[4];// for print + alrm->time.tm_year = buff[5] + 100 * cent_flag; + dev_info(dev, "PMU: read alarm: %d/%d/%d %d:%d:%d *****\n", + (alrm->time.tm_mon), alrm->time.tm_mday, (alrm->time.tm_year + os_ref_year), alrm->time.tm_hour, alrm->time.tm_min,alrm->time.tm_sec); alrm->time.tm_mon = buff[4] - 1; - alrm->time.tm_year = buff[5] + rtc_year_offset; - -// dev_info(dev->parent, "\n getting alarm time::\n"); -// print_time(dev, &alrm->time); + alrm->enabled = enabled_flag; return 0; } +static int ricoh619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct ricoh619_rtc *rtc = dev_get_drvdata(dev); + u8 buff[6]; + int err; + int cent_flag; + +// printk(KERN_INFO "PMU: %s\n", __func__); + err = 0; + ricoh619_rtc_alarm_enable(dev, 0); + if (rtc->irq == -1) + { + err = -EIO; + goto ERR; + } + + if(alrm->enabled== 0) + return 0; + + if (alrm->time.tm_year >= 100) + cent_flag = 1; + else + cent_flag = 0; + + alrm->time.tm_mon += 1; + print_time(dev->parent, &alrm->time); + buff[0] = alrm->time.tm_sec; + buff[1] = alrm->time.tm_min; + buff[2] = alrm->time.tm_hour; + buff[3] = alrm->time.tm_mday; + buff[4] = alrm->time.tm_mon; +// buff[5] = alrm->time.tm_year - rtc_year_offset; + buff[5] = alrm->time.tm_year - 100 * cent_flag; + convert_decimal_to_bcd(buff, sizeof(buff)); + buff[3] |= 0x80; /* set DAL_EXT */ + err = ricoh619_write_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff); + if (err) { + dev_err(dev->parent, "\n unable to set alarm\n"); + err = -EBUSY; + goto ERR; + } + + ricoh619_rtc_alarm_enable(dev, alrm->enabled); + +ERR: + return err; +} + static const struct rtc_class_ops ricoh619_rtc_ops = { .read_time = ricoh619_rtc_read_time, .set_time = ricoh619_rtc_set_time, .set_alarm = ricoh619_rtc_set_alarm, .read_alarm = ricoh619_rtc_read_alarm, + .alarm_irq_enable = ricoh619_rtc_alarm_enable, }; -static irqreturn_t ricoh619_rtc_irq(int irq, void *data) +static int ricoh619_rtc_alarm_flag_clr(struct device *dev) { - struct device *dev = data; - struct ricoh619_rtc *rtc = dev_get_drvdata(dev); - u8 reg; int err; + uint8_t reg_data; /* clear alarm-D status bits.*/ - err = ricoh619_read_regs(dev, rtc_ctrl2, 1, ®); + err = ricoh619_read_regs(dev, rtc_ctrl2, 1, ®_data); if (err) dev_err(dev->parent, "unable to read rtc_ctrl2 reg\n"); /* to clear alarm-D flag, and set adjustment parameter */ - reg &= ~0x81; - err = ricoh619_write_regs(dev, rtc_ctrl2, 1, ®); + reg_data &= ~0x81; + err = ricoh619_write_regs(dev, rtc_ctrl2, 1, ®_data); if (err) dev_err(dev->parent, "unable to program rtc_status reg\n"); + return err; +} +static irqreturn_t ricoh619_rtc_irq(int irq, void *data) +{ + struct device *dev = data; + struct ricoh619_rtc *rtc = dev_get_drvdata(dev); + +// printk(KERN_INFO "PMU: %s\n", __func__); + + ricoh619_rtc_alarm_flag_clr(dev); rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); return IRQ_HANDLED; @@ -285,103 +542,224 @@ static int __devinit ricoh619_rtc_probe(struct platform_device *pdev) struct ricoh619_rtc_platform_data *pdata = pdev->dev.platform_data; struct ricoh619_rtc *rtc; struct rtc_time tm; + uint8_t Pon_flag,Alarm_flag; int err; - u8 reg; - rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); -// printk("%s,line=%d\n", __func__,__LINE__); - - if (!rtc) - return -ENOMEM; + uint8_t buff[6]; - rtc->irq = -1; +// printk(KERN_INFO "******PMU RTC: Version 2013-08-01 REDS!******\n"); +// printk(KERN_INFO "PMU RTC: %s, ricoh619 driver run at 24H-mode\n", __func__); +// printk(KERN_INFO "PMU RTC: we never using periodic function and interrupt\n"); - if (!pdata) { + if(!pdata) + { dev_err(&pdev->dev, "no platform_data specified\n"); return -EINVAL; } - if (pdata->irq < 0) + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + if(IS_ERR(rtc)) + { + err = PTR_ERR(rtc); + dev_err(&pdev->dev, "no enough memory for ricoh619_rtc using\n"); + return err; + } + + dev_set_drvdata(&pdev->dev, rtc); + if(IS_ERR(rtc->rtc)) + { + err = PTR_ERR(rtc->rtc); + goto fail; + } + + if(pdata->irq < 0) + { dev_err(&pdev->dev, "\n no irq specified, wakeup is disabled\n"); + rtc->irq = -1; + rtc->irq_en = 0; + } + else + { + rtc->irq = pdata->irq; + rtc->irq_en = 1; + } - dev_set_drvdata(&pdev->dev, rtc); - device_init_wakeup(&pdev->dev, 1); - rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, - &ricoh619_rtc_ops, THIS_MODULE); + //get interrupt flag + err = ricoh619_rtc_alarm_is_enabled(&pdev->dev, &Alarm_flag); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: Disable alarm interrupt error\n"); + goto fail; - if (IS_ERR(rtc->rtc)) { - err = PTR_ERR(rtc->rtc); + } + + // get PON flag + err = ricoh619_rtc_Pon_get_clr(&pdev->dev, &Pon_flag); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: get PON flag error\n"); goto fail; } - reg = 0x60; /* to enable alarm_d and 24-hour format */ - err = ricoh619_write_regs(&pdev->dev, rtc_ctrl1, 1, ®); - if (err) { - dev_err(&pdev->dev, "failed rtc setup\n"); - return -EBUSY; + // disable rtc periodic function + err = ricoh619_rtc_periodic_disable(&pdev->dev); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: disable rtc periodic int error\n"); + goto fail; } - reg = 0; /* clearing RTC Adjust register */ - err = ricoh619_write_regs(&pdev->dev, rtc_adjust, 1, ®); - if (err) { + // clearing RTC Adjust register + err = ricoh619_rtc_clk_adjust(&pdev->dev, 0); + if(err) + { dev_err(&pdev->dev, "unable to program rtc_adjust reg\n"); - return -EBUSY; + err = -EBUSY; + goto fail; + } + + //disable interrupt + err = ricoh619_rtc_alarm_enable(&pdev->dev, 0); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: Disable alarm interrupt error\n"); + goto fail; } - /* Set default time-1970.1.1-0h:0m:0s if PON is on */ - err = ricoh619_read_regs(&pdev->dev, rtc_ctrl2, 1, ®); - if (err) { - dev_err(&pdev->dev, "\n failed to read rtc ctl2 reg\n"); - return -EBUSY; - } - if (reg&0x10) { - printk("%s,PON=1 -- CTRL2=%x\n", __func__, reg); - tm.tm_sec = 0; - tm.tm_min = 0; - tm.tm_hour = 0; - tm.tm_wday = 4; - tm.tm_mday = 1; - tm.tm_mon = 0; - tm.tm_year = 0x70; - /* VDET & PON = 0, others are not changed */ - reg &= ~0x50; - err = ricoh619_write_regs(&pdev->dev, rtc_ctrl2, 1, ®); - if (err) { - dev_err(&pdev->dev, "\n failed to write rtc ctl2 reg\n"); - return -EBUSY; - } - } else { - err = ricoh619_rtc_read_time(&pdev->dev, &tm); - if (err) { - dev_err(&pdev->dev, "\n failed to read time\n"); - return err; + // PON=1 + if(Pon_flag) + { + Alarm_flag = 0; + // clear int flag + err = ricoh619_rtc_alarm_flag_clr(&pdev->dev); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: Pon=1 clear alarm flag error\n"); + goto fail; } - } - if (ricoh619_rtc_valid_tm(&pdev->dev, &tm)) { - if (pdata->time.tm_year < 2000 || pdata->time.tm_year > 2100) { - memset(&pdata->time, 0, sizeof(pdata->time)); - pdata->time.tm_year = rtc_year_offset; - pdata->time.tm_mday = 1; - } else + + // using 24h-mode + err = ricoh619_rtc_hour_mode_set(&pdev->dev,1); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: Pon=1 set 24h-mode error\n"); + goto fail; + } + + // setting the default year +// printk(KERN_INFO "PMU: %s Set default time\n", __func__); + + pdata->time.tm_sec=0; + pdata->time.tm_min=0; + pdata->time.tm_hour=0; + pdata->time.tm_wday=6; + pdata->time.tm_mday=1; + pdata->time.tm_mon=1; + pdata->time.tm_year=2012; pdata->time.tm_year -= os_ref_year; - err = ricoh619_rtc_set_time(&pdev->dev, &pdata->time); - if (err) { - dev_err(&pdev->dev, "\n failed to set time\n"); - return err; + if(ricoh619_rtc_valid_tm(&pdev->dev, &(pdata->time)) == 0) + { + tm.tm_sec = pdata->time.tm_sec; + tm.tm_min = pdata->time.tm_min; + tm.tm_hour = pdata->time.tm_hour; + tm.tm_wday= pdata->time.tm_wday; + tm.tm_mday= pdata->time.tm_mday; + tm.tm_mon = pdata->time.tm_mon-1; + tm.tm_year = pdata->time.tm_year; + } + else + { + // using the ricoh default time instead of board default time + dev_err(&pdev->dev, "board rtc default is erro\n"); + tm.tm_sec = 0; + tm.tm_min = 0; + tm.tm_hour = 0; + tm.tm_wday = 4; + tm.tm_mday = 1; + tm.tm_mon = 0; + tm.tm_year = 70; + } + + // set default alarm time + if (tm.tm_year >= 100) + buff[5] = tm.tm_year-100-1; + else + buff[5] = tm.tm_year-1; + buff[0] = tm.tm_sec; + buff[1] = tm.tm_min; + buff[2] = tm.tm_hour; + buff[3] = tm.tm_mday; + buff[4] = tm.tm_mon +1; + + err = ricoh619_rtc_set_time(&pdev->dev, &tm); + if(err) + { + dev_err(&pdev->dev, "5t619 RTC:\n failed to set time\n"); + goto fail; } + + convert_decimal_to_bcd(buff, sizeof(buff)); + buff[3] |= 0x80; /* set DAL_EXT */ + + err = ricoh619_write_regs(&pdev->dev, rtc_alarm_y_sec, sizeof(buff), buff); + if (err) + printk( "\n unable to set alarm\n"); + } - if (pdata && (pdata->irq >= 0)) { - rtc->irq = pdata->irq + RICOH619_IRQ_DALE; + + device_init_wakeup(&pdev->dev, 1); + +// printk(KERN_INFO "PMU: %s register rtc device \n", __func__); + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &ricoh619_rtc_ops, THIS_MODULE); + + // set interrupt and enable it + if(rtc->irq != -1) + { + rtc->irq = rtc->irq + RICOH619_IRQ_DALE; err = request_threaded_irq(rtc->irq, NULL, ricoh619_rtc_irq, - IRQF_ONESHOT, "rtc_ricoh619", - &pdev->dev); - if (err) { + IRQF_ONESHOT, "rtc_ricoh619", &pdev->dev); + if(err) + { dev_err(&pdev->dev, "request IRQ:%d fail\n", rtc->irq); rtc->irq = -1; - } else { - device_init_wakeup(&pdev->dev, 1); + err = ricoh619_rtc_alarm_enable(&pdev->dev, 0); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: enable rtc alarm error\n"); + goto fail; + } + } + else + { + // enable wake enable_irq_wake(rtc->irq); + // enable alarm_d + err = ricoh619_rtc_alarm_enable(&pdev->dev, Alarm_flag); + if(err) + { + dev_err(&pdev->dev, "failed rtc setup\n"); + err = -EBUSY; + goto fail; + } } } + else + { + // system don't want to using alarm interrupt, so close it + err = ricoh619_rtc_alarm_enable(&pdev->dev, 0); + if(err) + { + dev_err(&pdev->dev, "5T619 RTC: Disable rtc alarm error\n"); + goto fail; + } + dev_err(&pdev->dev, "ricoh619 interrupt is disabled\n"); + } + + printk(KERN_INFO "RICOH619 RTC Register Success\n"); + + ricoh619_read_regs(&pdev->dev, rtc_ctrl1, 1,&buff[0]); + ricoh619_read_regs(&pdev->dev, rtc_ctrl2, 1,&buff[1]); +// printk(KERN_INFO "0xAE:%x 0xAF:%x\n",buff[0],buff[1]); return 0; fail: diff --git a/include/linux/power/ricoh619_battery.h b/include/linux/power/ricoh619_battery.h old mode 100755 new mode 100644 index d052eddf1a05..32738df9a807 --- a/include/linux/power/ricoh619_battery.h +++ b/include/linux/power/ricoh619_battery.h @@ -35,6 +35,8 @@ #define ADC_VDD_MV 2800 #define MIN_VOLTAGE 3100 #define MAX_VOLTAGE 4200 +#define B_VALUE 3435 + /* 619 Register information */ /* bank 0 */ @@ -54,6 +56,7 @@ #define REGISET1_REG 0xB6 #define REGISET2_REG 0xB7 #define CHGISET_REG 0xB8 +#define TIMSET_REG 0xB9 #define BATSET1_REG 0xBA #define BATSET2_REG 0xBB @@ -85,6 +88,8 @@ /* bank 1 */ /* Top address for battery initial setting */ #define BAT_INIT_TOP_REG 0xBC +#define TEMP_GAIN_H_REG 0xD6 +#define TEMP_OFF_H_REG 0xB8 #define BAT_REL_SEL_REG 0xDA #define BAT_TA_SEL_REG 0xDB /**************************/ diff --git a/include/linux/rtc/rtc-ricoh619.h b/include/linux/rtc/rtc-ricoh619.h index 317e7ef9364b..36c20f48d818 100755 --- a/include/linux/rtc/rtc-ricoh619.h +++ b/include/linux/rtc/rtc-ricoh619.h @@ -1,12 +1,12 @@ /* * include/linux/rtc/rtc-ricoh619.h * - * Real time clock driver for RICOH RC5T619 power management chip. + * Real time clock driver for RICOH R5T619 power management chip. * * Copyright (C) 2012-2013 RICOH COMPANY,LTD * * Based on code - * Copyright (C) 2011 NVIDIA Corporation + * Copyright (C) 2011 NVIDIA Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ * more details. * * you should have received a copy of the gnu general public license - * along with this program. If not, see . + * along with this program. If not, see . * */ #ifndef __LINUX_RTC_RICOH619_H_ @@ -32,6 +32,9 @@ #define rtc_seconds_reg 0xA0 #define rtc_alarm_y_sec 0xA8 #define rtc_adjust 0xA7 +#define rtc_month_reg 0xA5 +#define rtc_mday_reg 0xA4 +#define rtc_dal_month_reg 0xAC /* @@ -44,7 +47,6 @@ linux rtc driver refers 1900 as base year in many calculations. pmu rtc have only 2 nibbles to store year information, so using an offset of 100 to set the base year as 2000 for our driver. */ -#define rtc_year_offset 100 -- 2.34.1