Beispiel #1
0
static void __software_acr_update(struct battery_type *battery)
{
	static BOOL s_bFirstEntry = TRUE;
	static DWORD last_time_ms;
	DWORD now_time_ms = BAHW_MyGetMSecs();

	if (s_bFirstEntry) {
		s_bFirstEntry = FALSE;
		last_time_ms = now_time_ms;
	}

#if HTC_ENABLE_POWER_DEBUG
	printk(DRIVER_ZONE "+acr update: adc=%d C=%d mams=%d.\n",
		battery->charge_counter_adc,
		battery->charge_counter_mAh,
		battery->software_charge_counter_mAms);
#endif /* HTC_ENABLE_POWER_DEBUG*/

	__software_charge_counter_update(battery, now_time_ms - last_time_ms);
	__software_charge_counter_revise(battery, now_time_ms - last_time_ms);

#if HTC_ENABLE_POWER_DEBUG
	printk(DRIVER_ZONE "-acr update: adc=%d C=%d mams=%d.\n",
		battery->charge_counter_adc,
		battery->charge_counter_mAh,
		battery->software_charge_counter_mAms);
#endif /* HTC_ENABLE_POWER_DEBUG*/

	last_time_ms = now_time_ms;
}
Beispiel #2
0
BOOL do_power_alg(BOOL is_event_triggered)
{
	/* is_event_triggered - TRUE: handle event only, do not update capacity; FALSE; always update capacity*/
	static BOOL s_bFirstEntry = TRUE;
	static UINT32 s_pre_time_ms;
	static INT32 s_level;

	UINT32 now_time_ms = BAHW_MyGetMSecs();
#if !HTC_BATTERY_DS2746_DEBUG_ENABLE
	BOOL show_debug_message = FALSE;
#endif
	/*printk(DRIVER_ZONE "%s(%d) {\n",__func__, is_event_triggered);*/
	/*------------------------------------------------------
	1 get battery data and update charge state*/
	if (!battery_param_update(&poweralg.battery, &poweralg.protect_flags)){
		printk(DRIVER_ZONE "battery_param_update fail, please retry next time.\n");
		return FALSE;
	}

	update_next_charge_state();

	/*-----------------------------------------------------
	2 calculate battery capacity (predict if necessary)*/
	if (s_bFirstEntry || now_time_ms - s_pre_time_ms > 10000 || !is_event_triggered){
		/* DO not update capacity when plug/unplug cable less than 10 seconds*/
		__update_capacity();

		s_bFirstEntry = FALSE;
		s_pre_time_ms = now_time_ms;
	}

	if (config.debug_disable_shutdown){
		if (poweralg.capacity_01p <= 0){
			poweralg.capacity_01p = 1;
		}
	}

	s_level = CEILING(poweralg.capacity_01p, 10);
#if 0
	if (CEILING(poweralg.last_capacity_01p, 10) != s_level ||
		poweralg.battery.last_temp_01c != poweralg.battery.temp_01c) {

		poweralg.battery.last_temp_01c = poweralg.battery.temp_01c;
		poweralg.last_capacity_01p = poweralg.capacity_01p;
		ds2746_blocking_notify(DS2746_LEVEL_UPDATE, &s_level);
#if !HTC_BATTERY_DS2746_DEBUG_ENABLE
		show_debug_message = TRUE;
#endif
	}
#endif

	bounding_fullly_charged_level(config.full_level);

	/* is_superchg_software_charger_timeout: only triggered when superAC adapter in*/
	if (config.superchg_software_charger_timeout_sec && poweralg.is_super_ac
		&& FALSE==poweralg.is_superchg_software_charger_timeout){
		super_chg_on_time_sec += delta_time_sec;
		if (config.superchg_software_charger_timeout_sec <= super_chg_on_time_sec){
			printk(DRIVER_ZONE "superchg charger on timer timeout: %u sec\n",
				super_chg_on_time_sec);
			poweralg.is_superchg_software_charger_timeout = TRUE;
		}
	}
	/*------------------------------------------------------
	3 charging function change*/

	check_charging_function();

	/*------------------------------------------------------
	 4 debug messages and update battery change to userspace if need */
	/*powerlog_to_file(&poweralg);*/
	htc_battery_update_change();

#if HTC_BATTERY_DS2746_DEBUG_ENABLE
	printk(DRIVER_ZONE "S=%d P=%d chg=%d cable=%d%d%d flg=%d%d%d%d dbg=%d%d%d%d fst_dischg=%d/%d [%u]\n",
		poweralg.charge_state,
		poweralg.capacity_01p,
		poweralg.charging_enable,
		poweralg.is_cable_in,
		poweralg.is_china_ac_in,
		poweralg.is_super_ac,
		poweralg.protect_flags.is_charging_enable_available,
		poweralg.protect_flags.is_charging_high_current_avaialble,
		poweralg.protect_flags.is_battery_dead,
		poweralg.protect_flags.is_temperature_fault,
		config.debug_disable_shutdown,
		config.debug_fake_room_temp,
		config.debug_disable_hw_timer,
		config.debug_always_predict,
		poweralg.fst_discharge_capacity_01p,
		poweralg.fst_discharge_acr_mAh,
		BAHW_MyGetMSecs());
#else
	if (show_debug_message == TRUE)
		printk(DRIVER_ZONE "P=%d V=%d T=%d I=%d ACR=%d/%d KADC=%d charger=%d%d \n",
			poweralg.capacity_01p,
			poweralg.battery.voltage_mV,
			poweralg.battery.temp_01c,
			poweralg.battery.current_mA,
			poweralg.battery.charge_counter_mAh,
			poweralg.battery.charge_full_real_mAh,
			poweralg.battery.KADC_01p,
			poweralg.charging_source,
			poweralg.charging_enable);
#endif

	/*printk(DRIVER_ZONE "};\n");*/
	return TRUE;
}
Beispiel #3
0
static void update_next_charge_state(void)
{
	static UINT32 count_charging_full_condition;
	static UINT32 count_charge_over_load;
	int next_charge_state;
	int i;

	/*  unknown -> prediction -> unknown -> discharge/charging/pending
	charging -> full-wait-stable -> full-charging -> full-pending
	full-pending -> full-charging -> charging
	*(cable in group) -> discharge, charge-pending, dead
	*(cable out group), full-wait-stable, charge-pending, dead -> charging*/

	for (i = 0; i < 25; i++) /* maximun 25 times state transition to prevent from busy loop; ideally the transition time shall be less than 5 times.*/
	{
		/*printk(DRIVER_ZONE "%s.run[%d]: poweralg.charge_state=%d\n",
			__func__, i,poweralg.charge_state);*/
		next_charge_state = poweralg.charge_state;

		/* 0. enter prediction state or not*/
		if (poweralg.charge_state == CHARGE_STATE_UNKNOWN){
			if (poweralg.battery.is_prediction || config.debug_always_predict){
				if (poweralg.protect_flags.is_battery_dead){
					/* keep poweralg.charge_state unchanged, set capacity to 0% directly*/
					printk(DRIVER_ZONE " dead battery, p=0%% (skip prediction)\n");
					poweralg.capacity_01p = 0;
					battery_capacity_update(&poweralg.battery, poweralg.capacity_01p);

					poweralg.fst_discharge_capacity_01p = poweralg.capacity_01p;
					poweralg.fst_discharge_acr_mAh = poweralg.battery.charge_counter_mAh;
				}
				else{
					/* battery replaced, recalculate capacity based on battery voltage*/
					printk(DRIVER_ZONE " start predict discharge...\n");
					next_charge_state = CHARGE_STATE_PREDICTION;
				}

				config.debug_always_predict = FALSE;
			}
		}
		if (((poweralg.charge_state == CHARGE_STATE_UNKNOWN) ||
			(poweralg.charge_state == CHARGE_STATE_DISCHARGE))
			&& (200 < (poweralg.battery.KADC_01p - poweralg.battery.RARC_01p))) {
			printk(DRIVER_ZONE " KADC[%d] - RARC[%d] > 20%% => start prediction discharge...\n",
				poweralg.battery.KADC_01p/10, poweralg.battery.RARC_01p/10);
			next_charge_state = CHARGE_STATE_PREDICTION;
			poweralg.battery.is_prediction = TRUE;

		}

		if (next_charge_state == poweralg.charge_state){
			/*---------------------------------------------------------------------------------------------------*/
			/* 1. cable in group*/
			if (poweralg.charge_state == CHARGE_STATE_UNKNOWN ||
				poweralg.charge_state == CHARGE_STATE_CHARGING ||
				poweralg.charge_state == CHARGE_STATE_PENDING ||
				poweralg.charge_state == CHARGE_STATE_FULL_WAIT_STABLE ||
				poweralg.charge_state == CHARGE_STATE_FULL_CHARGING ||
				poweralg.charge_state == CHARGE_STATE_FULL_RECHARGING ||
				poweralg.charge_state == CHARGE_STATE_FULL_PENDING){
				if (!poweralg.is_cable_in){
					next_charge_state = CHARGE_STATE_DISCHARGE;
				}
				else if (!poweralg.protect_flags.is_charging_enable_available){
					next_charge_state = CHARGE_STATE_PENDING;
				}
			}

			/*---------------------------------------------------------------------------------------------------*/
			/* 2. cable out group*/
			if (poweralg.charge_state == CHARGE_STATE_UNKNOWN ||
				poweralg.charge_state == CHARGE_STATE_DISCHARGE){
				if (poweralg.is_cable_in){
					next_charge_state = CHARGE_STATE_CHARGING;
				}
			}
		}

		/*---------------------------------------------------------------------------------------------------*/
		/* 3. state handler/transition, if the charge state is not changed due to cable/protect flags*/
		if (next_charge_state == poweralg.charge_state){
			switch (poweralg.charge_state){
				case CHARGE_STATE_PREDICTION:
					{
						UINT32 end_time_ms = BAHW_MyGetMSecs();

						if (end_time_ms - poweralg.state_start_time_ms >=
							50 * 1000){
							/* symptom: time will shift a lot at booting */
							/* workaround: if time difference is unreasonable large (50 sec), ignore
								last start time, and reassign it as now. */
							poweralg.state_start_time_ms = end_time_ms;
							printk(DRIVER_ZONE "reassign prediction start timestamp as [%u]\n", end_time_ms);
						}
						else if (end_time_ms - poweralg.state_start_time_ms >=
							config.predict_timeout_sec * 1000){

							printk(DRIVER_ZONE "predict done [%u->%u]\n", poweralg.state_start_time_ms,
								end_time_ms);
							next_charge_state = CHARGE_STATE_UNKNOWN;
						}
					}
					break;
				case CHARGE_STATE_CHARGING:
					if (!poweralg.battery.is_prediction){
						/* -> full-charging, pending, dead*/
						if (poweralg.capacity_01p > 990){
							/* only ever charge-full, the capacity can be larger than 99.0%*/
							next_charge_state = CHARGE_STATE_FULL_CHARGING; // MATT: should be FULL_RECHARGING ?
						}
						else if (poweralg.battery.voltage_mV >= config.full_charging_mv &&
							poweralg.battery.current_mA >= 0 &&
							poweralg.battery.current_mA <= config.full_charging_ma){
							/* meet charge full terminate condition, check again*/
							next_charge_state = CHARGE_STATE_FULL_WAIT_STABLE;
						}
					}

					if (poweralg.battery.current_mA <= 0){
						/* count_charge_over_load is 5 as max*/
						if (count_charge_over_load < 5)
							count_charge_over_load++;
						else
							poweralg.is_charge_over_load = TRUE;
					}
					else{
						count_charge_over_load = 0;
						poweralg.is_charge_over_load = FALSE;
					}

					/* is_software_charger_timeout: only triggered when AC adapter in*/
					if (config.software_charger_timeout_sec && poweralg.is_china_ac_in){
						/* software charger timer is enabled; for AC charge only*/
						UINT32 end_time_ms = BAHW_MyGetMSecs();

						if (end_time_ms - poweralg.state_start_time_ms >=
							config.software_charger_timeout_sec * 1000){

							printk(DRIVER_ZONE "software charger timer timeout [%u->%u]\n",
								poweralg.state_start_time_ms,
								end_time_ms);
							poweralg.is_software_charger_timeout = TRUE;
						}
					}
					/* is_superchg_software_charger_timeout: only triggered when superAC adapter in*/
#if 0
					if (config.superchg_software_charger_timeout_sec && poweralg.is_super_ac
						&& FALSE==poweralg.is_superchg_software_charger_timeout){
						/* software charger timer is enabled; for superAC charge*/
						UINT32 end_time_ms = BAHW_MyGetMSecs();

						if (end_time_ms - poweralg.state_start_time_ms >=
							config.superchg_software_charger_timeout_sec * 1000){

							printk(DRIVER_ZONE "superchg software charger timer timeout [%d->%d]\n",
								poweralg.state_start_time_ms,
								end_time_ms);
							poweralg.is_superchg_software_charger_timeout = TRUE;
						}
					}
#endif
					/* Software should also toggle MCHG_EN within 4 hrs
						to prevent charger HW safety timer expired. */
#if 0
					if (config.charger_hw_safety_timer_watchdog_sec && poweralg.is_cable_in){
						UINT32 end_time_ms = BAHW_MyGetMSecs();
						if (end_time_ms - poweralg.last_charger_enable_toggled_time_ms >=
							config.charger_hw_safety_timer_watchdog_sec * 1000){
							poweralg.last_charger_enable_toggled_time_ms = BAHW_MyGetMSecs();
							poweralg.is_need_toggle_charger = TRUE;
							printk(DRIVER_ZONE "need software toggle charger [%d->%d]\n",
								poweralg.last_charger_enable_toggled_time_ms,
								end_time_ms);

						}
					}
#endif
					break;
				case CHARGE_STATE_FULL_WAIT_STABLE:
					{
						/* -> full-charging, pending, dead*/
						if (poweralg.battery.voltage_mV >= config.full_charging_mv &&
							poweralg.battery.current_mA >= 0 &&
							poweralg.battery.current_mA <= config.full_charging_ma){

							count_charging_full_condition++;
						}
						else{
							count_charging_full_condition = 0;
							next_charge_state = CHARGE_STATE_CHARGING;
						}

						if (count_charging_full_condition >= 3){

							poweralg.capacity_01p = 1000;
							battery_capacity_update(&poweralg.battery, poweralg.capacity_01p);

							next_charge_state = CHARGE_STATE_FULL_CHARGING;
						}
					}
					break;
				case CHARGE_STATE_FULL_CHARGING:
					{
						/* -> full-pending, charging*/
						UINT32 end_time_ms = BAHW_MyGetMSecs();

						if (poweralg.battery.voltage_mV < config.voltage_exit_full_mv){
							if (poweralg.capacity_01p > 990)
								poweralg.capacity_01p = 990;
							next_charge_state = CHARGE_STATE_CHARGING;
						}
						else if (config.full_pending_ma != 0 &&
							poweralg.battery.current_mA >= 0 &&
							poweralg.battery.current_mA <= config.full_pending_ma){

							printk(DRIVER_ZONE " charge-full pending(%dmA)(%u:%u)\n",
								poweralg.battery.current_mA,
								poweralg.state_start_time_ms,
								end_time_ms);

							next_charge_state = CHARGE_STATE_FULL_PENDING;
						}
						else if (end_time_ms - poweralg.state_start_time_ms >=
							config.full_charging_timeout_sec * 1000){

							printk(DRIVER_ZONE " charge-full (expect:%dsec)(%u:%u)\n",
								config.full_charging_timeout_sec,
								poweralg.state_start_time_ms,
								end_time_ms);
							next_charge_state = CHARGE_STATE_FULL_PENDING;
						}
					}
					break;
				case CHARGE_STATE_FULL_PENDING:
					if ((poweralg.battery.voltage_mV >= 0 &&
						poweralg.battery.voltage_mV < config.voltage_recharge_mv) ||
						(poweralg.battery.RARC_01p >= 0 &&
						poweralg.battery.RARC_01p <= config.capacity_recharge_p * 10)){
						/* -> full-recharging*/
						next_charge_state = CHARGE_STATE_FULL_RECHARGING;
					}
					break;
				case CHARGE_STATE_FULL_RECHARGING:
					{
						if (poweralg.battery.voltage_mV < config.voltage_exit_full_mv){
							if (poweralg.capacity_01p > 990)
								poweralg.capacity_01p = 990;
							next_charge_state = CHARGE_STATE_CHARGING;
						}
						else if (poweralg.battery.voltage_mV >= config.full_charging_mv &&
							poweralg.battery.current_mA >= 0 &&
							poweralg.battery.current_mA <= config.full_charging_ma){
							/* meet charge full terminate condition, check again*/
							next_charge_state = CHARGE_STATE_FULL_CHARGING;
						}
					}
					break;
				case CHARGE_STATE_PENDING:
				case CHARGE_STATE_DISCHARGE:
					{
						UINT32 end_time_ms = BAHW_MyGetMSecs();

						if (!poweralg.is_voltage_stable){
							if (end_time_ms - poweralg.state_start_time_ms >=
								config.wait_votlage_statble_sec * 1000){

								printk(DRIVER_ZONE " voltage stable\n");
								poweralg.is_voltage_stable = TRUE;
							}
						}
					}

					if (poweralg.is_cable_in &&
						poweralg.protect_flags.is_charging_enable_available){
						/* -> charging*/
						next_charge_state = CHARGE_STATE_CHARGING;
					}
					break;
			}
		}

		/*---------------------------------------------------------------------------------------------------*/
		/* 4. state transition*/
		if (next_charge_state != poweralg.charge_state){
			/* state exit*/
			switch (poweralg.charge_state){
				case CHARGE_STATE_UNKNOWN:
					poweralg.capacity_01p = poweralg.battery.RARC_01p;
					if (poweralg.capacity_01p > 990)
						poweralg.capacity_01p = 990;
					if (poweralg.capacity_01p < 0)
						poweralg.capacity_01p = 0;

					poweralg.fst_discharge_capacity_01p = poweralg.capacity_01p;
					poweralg.fst_discharge_acr_mAh = poweralg.battery.charge_counter_mAh;
					break;
				case CHARGE_STATE_PREDICTION:
					battery_param_update(&poweralg.battery,
						&poweralg.protect_flags);

					poweralg.capacity_01p = poweralg.battery.KADC_01p;
					if (poweralg.capacity_01p > 990)
						poweralg.capacity_01p = 990;
					if (poweralg.capacity_01p < 0)
						poweralg.capacity_01p = 0;
					battery_capacity_update(&poweralg.battery,
						poweralg.capacity_01p);

					poweralg.fst_discharge_capacity_01p = poweralg.capacity_01p;
					poweralg.fst_discharge_acr_mAh = poweralg.battery.charge_counter_mAh;
					break;
			}

			/* state init*/
			poweralg.state_start_time_ms = BAHW_MyGetMSecs();

			switch (next_charge_state){
				case CHARGE_STATE_DISCHARGE:
				case CHARGE_STATE_PENDING:
					/*! star_lee 20100426 - always set ACR=FULL when discharge starts and ACR>FULL*/
					if (poweralg.battery.RARC_01p > 1000)
						battery_capacity_update(&poweralg.battery, 1000);

					poweralg.is_need_calibrate_at_49p = TRUE;
					poweralg.is_need_calibrate_at_14p = TRUE;
					poweralg.fst_discharge_capacity_01p = poweralg.capacity_01p;
					poweralg.fst_discharge_acr_mAh = poweralg.battery.charge_counter_mAh;
					poweralg.is_voltage_stable = FALSE;

					break;
				case CHARGE_STATE_CHARGING:
					poweralg.is_need_toggle_charger = FALSE;
					poweralg.last_charger_enable_toggled_time_ms = BAHW_MyGetMSecs();
					poweralg.is_software_charger_timeout = FALSE;   /* reset software charger timer every time when charging re-starts*/
					poweralg.is_charge_over_load = FALSE;
					count_charge_over_load = 0;
					poweralg.battery.charge_full_real_mAh = poweralg.battery.charge_full_design_mAh;
					battery_capacity_update(&poweralg.battery, poweralg.capacity_01p);
					break;
				case CHARGE_STATE_FULL_WAIT_STABLE:
					/* set to 0 first; the cournter will be add to 1 soon in CHARGE_STATE_FULL_WAIT_STABLE state handler*/
					count_charging_full_condition = 0;
					break;
			}

			printk(DRIVER_ZONE " state change(%d->%d), full count=%d, over load count=%d [%u]\n",
				poweralg.charge_state,
				next_charge_state,
				count_charging_full_condition,
				count_charge_over_load,
				poweralg.state_start_time_ms);

			poweralg.charge_state = next_charge_state;
			continue;
		}

		break;
	}
}