Esempio n. 1
0
static void low_comp_work_handler(struct work_struct *work)
{
	struct battery_data *battery =
		container_of(work, struct battery_data, low_comp_work.work);
	int fg_soc;
	int fg_vcell;
	int fg_current;	
	int i, comp_result;

	fg_soc = battery->info.level;

	for (i = 0 ; i<10 ; i++) {
		fg_vcell = get_fuelgauge_value(FG_VOLTAGE);
		fg_current = get_fuelgauge_value(FG_CURRENT);
		pr_info("%s : running", __func__);

		comp_result = p3_low_batt_compensation(fg_soc, fg_vcell, fg_current);
		if (comp_result == 2) {
			pr_info("%s : soc(%d), vcell(%d), current(%d), count(%d), pre_count(%d), pre_condition(%d)\n",
				__func__, fg_soc, fg_vcell, fg_current, i,
				max17042_chip_data->pre_cond_ok, max17042_chip_data->low_comp_pre_cond);
			break;
		}
		else if (comp_result == 1) {
			pr_info("%s : low compensation occurred!, vcell(%d), current(%d)\n",
				__func__, fg_vcell, fg_current);
			wake_lock(&battery->work_wake_lock);
			schedule_work(&battery->battery_work);
			break;
		}
		msleep(2000);
	}
	wake_unlock(&battery->low_comp_wake_lock);
}
static bool check_UV_charging_case(void)
{
	int fg_vcell = get_fuelgauge_value(FG_VOLTAGE);
	int fg_current = get_fuelgauge_value(FG_CURRENT);
	int threshold = 0;

	if (get_fuelgauge_value(FG_BATTERY_TYPE) == SDI_BATTERY_TYPE)
		threshold = 3300 + ((fg_current * 17) / 100);
	else if (get_fuelgauge_value(FG_BATTERY_TYPE) == ATL_BATTERY_TYPE)
		threshold = 3300 + ((fg_current * 13) / 100);

	if (fg_vcell <= threshold)
		return 1;
	else
		return 0;
}
static void fuelgauge_work_handler(struct work_struct *work)
{
	struct battery_data *battery =
		container_of(work, struct battery_data, fuelgauge_work.work);
	pr_info("low battery alert!");
	if (get_fuelgauge_value(FG_CHECK_STATUS))
		_low_battery_alarm_(battery);
}
static void full_comp_work_handler(struct work_struct *work)
{
	struct battery_data *battery =
		container_of(work, struct battery_data, full_comp_work.work);
	int avg_current = get_fuelgauge_value(FG_CURRENT_AVG);

	if (avg_current >= 25) {
		cancel_delayed_work(&battery->full_comp_work);
		schedule_delayed_work(&battery->full_comp_work, 100);
	} else {
		pr_info("%s: full charge compensation start (avg_current %d)\n",
			__func__, avg_current);
		fg_fullcharged_compensation(
			battery->full_charge_comp_recharge_info, 0);
	}
}
static ssize_t p3_bat_show_property(struct device *dev,
			struct device_attribute *attr,
			char *buf)
{
	int i = 0;
#ifdef CONFIG_MACH_SAMSUNG_P5	
	s32 temp = 0;
#endif	
	u8 batt_str[5];
	const ptrdiff_t off = attr - p3_battery_attrs;

	switch (off) {
	case BATT_VOL:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
		get_fuelgauge_value(FG_VOLTAGE));
		break;
	case BATT_TEMP:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
		test_batterydata->info.batt_temp);
		break;
#ifdef CONFIG_MACH_SAMSUNG_P5		
	case BATT_TEMP_CELS:
			temp = ((test_batterydata->info.batt_temp) / 10);
			i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			temp);
			break;
#endif			
	case BATT_CHARGING_SOURCE:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
		test_batterydata->info.charging_source);
		break;
	case BATT_FG_SOC:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
		get_fuelgauge_value(FG_LEVEL));
		break;
	case BATT_BATT_TYPE:
		if (get_fuelgauge_value(FG_BATTERY_TYPE) == SDI_BATTERY_TYPE)
			sprintf(batt_str, "SDI");
		else if (get_fuelgauge_value(FG_BATTERY_TYPE) ==
			ATL_BATTERY_TYPE)
			sprintf(batt_str, "ATL");
		i += scnprintf(buf + i, PAGE_SIZE - i, "%s_%s\n",
		batt_str, batt_str);
		break;
	case BATT_TEMP_CHECK:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
		test_batterydata->info.batt_health);
		break;
	case BATT_FULL_CHECK:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
		test_batterydata->info.batt_is_full);
		break;
#ifdef CONFIG_SAMSUNG_LPM_MODE
	case CHARGING_MODE_BOOTING:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			test_batterydata->charging_mode_booting);
		break;
	case VOLTAGE_NOW:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			get_fuelgauge_value(FG_VOLTAGE));
		break;
#endif
	default:
		i = -EINVAL;
	}

	return i;
}
static int p3_get_bat_temp(struct power_supply *bat_ps)
{
	struct battery_data *battery = container_of(bat_ps,
				struct battery_data, psy_battery);
	int health = battery->info.batt_health;
	int update = 0;
	int battery_temp;
	int temp_high_threshold;
	int temp_high_recovery;
	int temp_low_threshold;
	int temp_low_recovery;

#ifdef CONFIG_MACH_SAMSUNG_P4LTE
	extern int charging_mode_from_boot;
#endif

	battery_temp = get_fuelgauge_value(FG_TEMPERATURE);

	temp_high_threshold = battery->pdata->temp_high_threshold;
	temp_high_recovery = battery->pdata->temp_high_recovery;
	temp_low_threshold = battery->pdata->temp_low_threshold;
	temp_low_recovery = battery->pdata->temp_low_recovery;

#ifdef CONFIG_MACH_SAMSUNG_P4LTE
	if (charging_mode_from_boot) {
		temp_high_threshold = battery->pdata->temp_high_threshold_lpm;
		temp_high_recovery = battery->pdata->temp_high_recovery_lpm;
		temp_low_threshold = battery->pdata->temp_low_threshold_lpm;
		temp_low_recovery = battery->pdata->temp_low_recovery_lpm;
	}
#endif

#ifdef __TEST_DEVICE_DRIVER__
	switch (bat_temp_force_state) {
	case 0:
		break;
	case 1:
		battery_temp = temp_high_threshold + 1;
		break;
	case 2:
		battery_temp = temp_low_threshold - 1;
		break;
	default:
		break;
	}
#endif /* __TEST_DEVICE_DRIVER__ */

	if (battery_temp >= temp_high_threshold) {
		if (health != POWER_SUPPLY_HEALTH_OVERHEAT &&
				health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) {
			p3_temp_control(battery, POWER_SUPPLY_HEALTH_OVERHEAT);
			update = 1;
		}
	} else if (battery_temp <= temp_high_recovery &&
			battery_temp >= temp_low_recovery) {
		if (health == POWER_SUPPLY_HEALTH_OVERHEAT ||
				health == POWER_SUPPLY_HEALTH_COLD) {
			p3_temp_control(battery, POWER_SUPPLY_HEALTH_GOOD);
			update = 1;
		}
	} else if (battery_temp <= temp_low_threshold) {
		if (health != POWER_SUPPLY_HEALTH_COLD &&
				health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) {
			p3_temp_control(battery, POWER_SUPPLY_HEALTH_COLD);
			update = 1;
		}
	}

	if (update)
		pr_info("p3_get_bat_temp = %d.", battery_temp);

	return battery_temp/100;
}
static int p3_get_bat_level(struct power_supply *bat_ps)
{
	struct battery_data *battery = container_of(bat_ps,
				struct battery_data, psy_battery);
	int fg_soc;
	int fg_vfsoc;
	int fg_vcell;
	int fg_current;
	int avg_current;
	int recover_flag = 0;

	recover_flag = fg_check_cap_corruption();

	/* check VFcapacity every five minutes */
	if (!(battery->fg_chk_cnt++ % 10)) {
		fg_check_vf_fullcap_range();
		battery->fg_chk_cnt = 1;
	}

	fg_soc = get_fuelgauge_value(FG_LEVEL);
	if (fg_soc < 0) {
		pr_info("Can't read soc!!!");
		fg_soc = battery->info.level;
	}

	if (!check_jig_on() && !max17042_chip_data->info.low_batt_comp_flag) {
		if (((fg_soc+5) < max17042_chip_data->info.previous_repsoc) ||
			(fg_soc > (max17042_chip_data->info.previous_repsoc+5)))
			battery->fg_skip = 1;
	}

	/* skip one time (maximum 30 seconds) because of corruption. */
	if (battery->fg_skip) {
		pr_info("%s: skip update until corruption check "
			"is done (fg_skip_cnt:%d)\n",
			__func__, ++battery->fg_skip_cnt);
		fg_soc = battery->info.level;
		if (recover_flag || battery->fg_skip_cnt > 10) {
			battery->fg_skip = 0;
			battery->fg_skip_cnt = 0;
		}
	}

	if (battery->low_batt_boot_flag) {
		fg_soc = 0;

		if (check_ta_conn(battery) && !check_UV_charging_case()) {
			fg_adjust_capacity();
			battery->low_batt_boot_flag = 0;
		}

		if (!check_ta_conn(battery))
			battery->low_batt_boot_flag = 0;
	}

	fg_vcell = get_fuelgauge_value(FG_VOLTAGE);
	if (fg_vcell < 0) {
		pr_info("Can't read vcell!!!");
		fg_vcell = battery->info.batt_vol;
	} else
		battery->info.batt_vol = fg_vcell;

	fg_current = get_fuelgauge_value(FG_CURRENT);
	avg_current = get_fuelgauge_value(FG_CURRENT_AVG);
	fg_vfsoc = get_fuelgauge_value(FG_VF_SOC);

	// Algorithm for reducing time to fully charged (from MAXIM)
	if(battery->info.charging_enabled &&  // Charging is enabled
		!battery->info.batt_is_recharging &&  // Not Recharging
		battery->info.charging_source == CHARGER_AC &&  // Only AC (Not USB cable)
		!battery->is_first_check &&  // Skip when first check after boot up
		(fg_vfsoc>70 && (fg_current>20 && fg_current<250) &&
		(avg_current>20 && avg_current<260))) {

		if(battery->full_check_flag == 2) {
			pr_info("%s: force fully charged SOC !! (%d)", __func__, battery->full_check_flag);
			fg_set_full_charged();
			fg_soc = get_fuelgauge_value(FG_LEVEL);
		}
		else if(battery->full_check_flag < 2)
			pr_info("%s: full_check_flag (%d)", __func__, battery->full_check_flag);

		if(battery->full_check_flag++ > 10000)  // prevent overflow
			battery->full_check_flag = 3;
	}
	else
		battery->full_check_flag = 0;

	if (battery->info.charging_source == CHARGER_AC &&
		battery->info.batt_improper_ta == 0) {
		if (is_over_abs_time(battery)) {
			fg_soc = 100;
			battery->info.batt_is_full = 1;
			pr_info("%s: charging time is over", __func__);
			pr_info("%s: fg_vcell = %d, fg_soc = %d,"
				" is_full = %d\n",
				__func__, fg_vcell, fg_soc,
				battery->info.batt_is_full);
			p3_set_chg_en(battery, 0);
			goto __end__;
		}
	}

	if (fg_vcell <= battery->pdata->recharge_voltage) {
		if (battery->info.batt_is_full &&
			!battery->info.charging_enabled) {
			if (++battery->recharging_cnt > 1) {
				pr_info("recharging(under full)");
				battery->info.batt_is_recharging = 1;
				p3_set_chg_en(battery, 1);
				battery->recharging_cnt = 0;
				pr_info("%s: fg_vcell = %d, fg_soc = %d,"
					" is_recharging = %d\n",
					__func__, fg_vcell, fg_soc,
					battery->info.batt_is_recharging);
			}
		} else
			battery->recharging_cnt = 0;
	} else
		battery->recharging_cnt = 0;

	if (fg_soc > 100)
		fg_soc = 100;

	/*  Checks vcell level and tries to compensate SOC if needed.*/
	/*  If jig cable is connected, then skip low batt compensation check. */
	if (!check_jig_on() && !battery->info.charging_enabled)
		fg_soc = p3_low_batt_compensation(fg_soc, fg_vcell, fg_current);

__end__:
	pr_debug("fg_vcell = %d, fg_soc = %d, is_full = %d",
		fg_vcell, fg_soc, battery->info.batt_is_full);

	if(battery->is_first_check)
		battery->is_first_check = false;

	if (battery->info.batt_is_full &&
		(battery->info.charging_source != CHARGER_USB))
		fg_soc = 100;
#if 0 // not used
	else {
		if (fg_soc >= 100)
			fg_soc = 99;
	}
#endif
	return fg_soc;
}