static void ab8500_chargalg_algorithm()

in supply/ab8500_chargalg.c [1300:1637]


static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
{
	struct power_supply_battery_info *bi = di->bm->bi;
	int charger_status;
	int ret;
	int curr_step_lvl_ua;

	/* Collect data from all power_supply class devices */
	class_for_each_device(power_supply_class, NULL,
		di->chargalg_psy, ab8500_chargalg_get_ext_psy_data);

	ab8500_chargalg_end_of_charge(di);
	ab8500_chargalg_check_temp(di);
	ab8500_chargalg_check_charger_voltage(di);

	charger_status = ab8500_chargalg_check_charger_connection(di);
	ab8500_chargalg_check_current_step_status(di);

	if (is_ab8500(di->parent)) {
		ret = ab8500_chargalg_check_charger_enable(di);
		if (ret < 0)
			dev_err(di->dev, "Checking charger is enabled error"
					": Returned Value %d\n", ret);
	}

	/*
	 * First check if we have a charger connected.
	 * Also we don't allow charging of unknown batteries if configured
	 * this way
	 */
	if (!charger_status ||
		(di->events.batt_unknown && !di->bm->chg_unknown_bat)) {
		if (di->charge_state != STATE_HANDHELD) {
			di->events.safety_timer_expired = false;
			ab8500_chargalg_state_to(di, STATE_HANDHELD_INIT);
		}
	}

	/* If suspended, we should not continue checking the flags */
	else if (di->charge_state == STATE_SUSPENDED_INIT ||
		di->charge_state == STATE_SUSPENDED) {
		/* We don't do anything here, just don,t continue */
	}

	/* Safety timer expiration */
	else if (di->events.safety_timer_expired) {
		if (di->charge_state != STATE_SAFETY_TIMER_EXPIRED)
			ab8500_chargalg_state_to(di,
				STATE_SAFETY_TIMER_EXPIRED_INIT);
	}
	/*
	 * Check if any interrupts has occured
	 * that will prevent us from charging
	 */

	/* Battery removed */
	else if (di->events.batt_rem) {
		if (di->charge_state != STATE_BATT_REMOVED)
			ab8500_chargalg_state_to(di, STATE_BATT_REMOVED_INIT);
	}
	/* Main or USB charger not ok. */
	else if (di->events.mainextchnotok || di->events.usbchargernotok) {
		/*
		 * If vbus_collapsed is set, we have to lower the charger
		 * current, which is done in the normal state below
		 */
		if (di->charge_state != STATE_CHG_NOT_OK &&
				!di->events.vbus_collapsed)
			ab8500_chargalg_state_to(di, STATE_CHG_NOT_OK_INIT);
	}
	/* VBUS, Main or VBAT OVV. */
	else if (di->events.vbus_ovv ||
			di->events.main_ovv ||
			di->events.batt_ovv ||
			!di->chg_info.usb_chg_ok ||
			!di->chg_info.ac_chg_ok) {
		if (di->charge_state != STATE_OVV_PROTECT)
			ab8500_chargalg_state_to(di, STATE_OVV_PROTECT_INIT);
	}
	/* USB Thermal, stop charging */
	else if (di->events.main_thermal_prot ||
		di->events.usb_thermal_prot) {
		if (di->charge_state != STATE_HW_TEMP_PROTECT)
			ab8500_chargalg_state_to(di,
				STATE_HW_TEMP_PROTECT_INIT);
	}
	/* Battery temp over/under */
	else if (di->events.btemp_underover) {
		if (di->charge_state != STATE_TEMP_UNDEROVER)
			ab8500_chargalg_state_to(di,
				STATE_TEMP_UNDEROVER_INIT);
	}
	/* Watchdog expired */
	else if (di->events.ac_wd_expired ||
		di->events.usb_wd_expired) {
		if (di->charge_state != STATE_WD_EXPIRED)
			ab8500_chargalg_state_to(di, STATE_WD_EXPIRED_INIT);
	}
	/* Battery temp high/low */
	else if (di->events.btemp_lowhigh) {
		if (di->charge_state != STATE_TEMP_LOWHIGH)
			ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH_INIT);
	}

	dev_dbg(di->dev,
		"[CHARGALG] Vb %d Ib_avg %d Ib_inst %d Tb %d Cap %d Maint %d "
		"State %s Active_chg %d Chg_status %d AC %d USB %d "
		"AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d "
		"USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n",
		di->batt_data.volt_uv,
		di->batt_data.avg_curr_ua,
		di->batt_data.inst_curr_ua,
		di->batt_data.temp,
		di->batt_data.percent,
		di->maintenance_chg,
		states[di->charge_state],
		di->chg_info.charger_type,
		di->charge_status,
		di->chg_info.conn_chg & AC_CHG,
		di->chg_info.conn_chg & USB_CHG,
		di->chg_info.online_chg & AC_CHG,
		di->chg_info.online_chg & USB_CHG,
		di->events.ac_cv_active,
		di->events.usb_cv_active,
		di->chg_info.ac_curr_ua,
		di->chg_info.usb_curr_ua,
		di->chg_info.ac_vset_uv,
		di->chg_info.ac_iset_ua,
		di->chg_info.usb_vset_uv,
		di->chg_info.usb_iset_ua);

	switch (di->charge_state) {
	case STATE_HANDHELD_INIT:
		ab8500_chargalg_stop_charging(di);
		di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
		ab8500_chargalg_state_to(di, STATE_HANDHELD);
		fallthrough;

	case STATE_HANDHELD:
		break;

	case STATE_SUSPENDED_INIT:
		if (di->susp_status.ac_suspended)
			ab8500_chargalg_ac_en(di, false, 0, 0);
		if (di->susp_status.usb_suspended)
			ab8500_chargalg_usb_en(di, false, 0, 0);
		ab8500_chargalg_stop_safety_timer(di);
		ab8500_chargalg_stop_maintenance_timer(di);
		di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
		di->maintenance_chg = false;
		ab8500_chargalg_state_to(di, STATE_SUSPENDED);
		power_supply_changed(di->chargalg_psy);
		fallthrough;

	case STATE_SUSPENDED:
		/* CHARGING is suspended */
		break;

	case STATE_BATT_REMOVED_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_BATT_REMOVED);
		fallthrough;

	case STATE_BATT_REMOVED:
		if (!di->events.batt_rem)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_HW_TEMP_PROTECT_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_HW_TEMP_PROTECT);
		fallthrough;

	case STATE_HW_TEMP_PROTECT:
		if (!di->events.main_thermal_prot &&
				!di->events.usb_thermal_prot)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_OVV_PROTECT_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_OVV_PROTECT);
		fallthrough;

	case STATE_OVV_PROTECT:
		if (!di->events.vbus_ovv &&
				!di->events.main_ovv &&
				!di->events.batt_ovv &&
				di->chg_info.usb_chg_ok &&
				di->chg_info.ac_chg_ok)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_CHG_NOT_OK_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_CHG_NOT_OK);
		fallthrough;

	case STATE_CHG_NOT_OK:
		if (!di->events.mainextchnotok &&
				!di->events.usbchargernotok)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_SAFETY_TIMER_EXPIRED_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_SAFETY_TIMER_EXPIRED);
		fallthrough;

	case STATE_SAFETY_TIMER_EXPIRED:
		/* We exit this state when charger is removed */
		break;

	case STATE_NORMAL_INIT:
		if (di->curr_status.curr_step_ua == CHARGALG_CURR_STEP_LOW_UA)
			ab8500_chargalg_stop_charging(di);
		else {
			curr_step_lvl_ua = bi->constant_charge_current_max_ua
				* di->curr_status.curr_step_ua
				/ CHARGALG_CURR_STEP_HIGH_UA;
			ab8500_chargalg_start_charging(di,
				bi->constant_charge_voltage_max_uv,
				curr_step_lvl_ua);
		}

		ab8500_chargalg_state_to(di, STATE_NORMAL);
		ab8500_chargalg_start_safety_timer(di);
		ab8500_chargalg_stop_maintenance_timer(di);
		init_maxim_chg_curr(di);
		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
		di->eoc_cnt = 0;
		di->maintenance_chg = false;
		power_supply_changed(di->chargalg_psy);

		break;

	case STATE_NORMAL:
		handle_maxim_chg_curr(di);
		if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
			di->maintenance_chg) {
			if (di->bm->no_maintenance)
				ab8500_chargalg_state_to(di,
					STATE_WAIT_FOR_RECHARGE_INIT);
			else
				ab8500_chargalg_state_to(di,
					STATE_MAINTENANCE_A_INIT);
		}
		break;

	/* This state will be used when the maintenance state is disabled */
	case STATE_WAIT_FOR_RECHARGE_INIT:
		ab8500_chargalg_hold_charging(di);
		ab8500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE);
		fallthrough;

	case STATE_WAIT_FOR_RECHARGE:
		if (di->batt_data.percent <= AB8500_RECHARGE_CAP)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_MAINTENANCE_A_INIT:
		ab8500_chargalg_stop_safety_timer(di);
		ab8500_chargalg_start_maintenance_timer(di,
			di->bm->bat_type->maint_a_chg_timer_h);
		ab8500_chargalg_start_charging(di,
			di->bm->bat_type->maint_a_vol_lvl,
			di->bm->bat_type->maint_a_cur_lvl);
		ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A);
		power_supply_changed(di->chargalg_psy);
		fallthrough;

	case STATE_MAINTENANCE_A:
		if (di->events.maintenance_timer_expired) {
			ab8500_chargalg_stop_maintenance_timer(di);
			ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B_INIT);
		}
		break;

	case STATE_MAINTENANCE_B_INIT:
		ab8500_chargalg_start_maintenance_timer(di,
			di->bm->bat_type->maint_b_chg_timer_h);
		ab8500_chargalg_start_charging(di,
			di->bm->bat_type->maint_b_vol_lvl,
			di->bm->bat_type->maint_b_cur_lvl);
		ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B);
		power_supply_changed(di->chargalg_psy);
		fallthrough;

	case STATE_MAINTENANCE_B:
		if (di->events.maintenance_timer_expired) {
			ab8500_chargalg_stop_maintenance_timer(di);
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		}
		break;

	case STATE_TEMP_LOWHIGH_INIT:
		ab8500_chargalg_start_charging(di,
			di->bm->bat_type->low_high_vol_lvl,
			di->bm->bat_type->low_high_cur_lvl);
		ab8500_chargalg_stop_maintenance_timer(di);
		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
		ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH);
		power_supply_changed(di->chargalg_psy);
		fallthrough;

	case STATE_TEMP_LOWHIGH:
		if (!di->events.btemp_lowhigh)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_WD_EXPIRED_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_WD_EXPIRED);
		fallthrough;

	case STATE_WD_EXPIRED:
		if (!di->events.ac_wd_expired &&
				!di->events.usb_wd_expired)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;

	case STATE_TEMP_UNDEROVER_INIT:
		ab8500_chargalg_stop_charging(di);
		ab8500_chargalg_state_to(di, STATE_TEMP_UNDEROVER);
		fallthrough;

	case STATE_TEMP_UNDEROVER:
		if (!di->events.btemp_underover)
			ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
		break;
	}

	/* Start charging directly if the new state is a charge state */
	if (di->charge_state == STATE_NORMAL_INIT ||
			di->charge_state == STATE_MAINTENANCE_A_INIT ||
			di->charge_state == STATE_MAINTENANCE_B_INIT)
		queue_work(di->chargalg_wq, &di->chargalg_work);
}