FreeCalypso > hg > fc-tourmaline
view src/cs/drivers/drv_app/fchg/fchg_process.c @ 223:740a8e8fc9d7
startup sync logic rework for the new PWON button boot scheme
Previously we added logic to the MMI task to hold off PEI init until
R2D is running, and then extended that condition to wait for FCHG
init too. However, the dependencies of MMI upon R2D and FCHG don't
start until mmiInit(), and that call is driven by Switch_ON() code,
hence the wait for R2D and FCHG init can be made in that code path
instead of the MMI task. Furthermore, with our new way of signaling
PWON button boot to MMI, we need a new wait to ensure that the MMI
task is up - previously this assurance was provided by the wait for
Kp pointers to be set.
Solution: revert our previous PEI init hold-off additions to MMI,
add a new flag indicating MMI task init done, and put the combined
wait for all needed conditions into our new PWON button boot code
in power.c.
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Tue, 27 Apr 2021 06:24:52 +0000 |
| parents | 75067af48bfd |
| children | 3c790d29748e |
line wrap: on
line source
/* * In this module we are going to implement the main process functions * for FCHG. */ #include "fchg/fchg_env.h" #include "fchg/fchg_func_i.h" #include "rv/rv_general.h" #include "rvf/rvf_api.h" #include "rvm/rvm_use_id_list.h" #include "abb/abb.h" #include "fc-target.h" #include <string.h> #include <stdio.h> extern UINT16 madc_vbat_2_physical(UINT16 adc_val); extern UINT16 madc_vbat_inverse(UINT16 mv); #if defined(CONFIG_TARGET_C155) || defined(CONFIG_TARGET_J100) #define LEDC 0x20 #else #define LEDC 0 #endif void pwr_init_discharge(void) { pwr_ctrl->curr_disch_thresh = 0; } static void handle_discharge(void) { UINT16 i; char trace[64]; /* first we need to find the current threshold we are at */ i = pwr_ctrl->curr_disch_thresh; /* are we at the bottom? */ if ((i + 1) == pwr_ctrl->nb_percent_thresh) return; /* are we crossing our current threshold? */ if (pwr_ctrl->batt_mv >= pwr_ctrl->batt.percent_thresh[i].bat_voltage) return; /* yes, we crossed it - see if we fell even further down */ while (i < pwr_ctrl->nb_percent_thresh-1 && pwr_ctrl->batt_mv < pwr_ctrl->batt.percent_thresh[i].bat_voltage) i++; /* the last one was it */ pwr_ctrl->curr_disch_thresh = i; sprintf(trace, "Battery fell through %u%% mark", pwr_ctrl->batt.percent_thresh[i-1].remain_capa); rvf_send_trace(trace, strlen(trace), NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID); if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_DISCHARGE); } static void start_i2v_cal(void) { UINT16 bciconf; rvf_send_trace("Calibrating i2v offset", 22, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_I2V_CAL_2; bciconf = ABB_Read_Register_on_page(PAGE1, BCICONF); bciconf &= 0x3E0; bciconf |= pwr_ctrl->config.bciconf; ABB_Write_Register_on_page(PAGE1, BCICONF, bciconf); /* * Set the CHDISPA bit and start the zero calibration routine * of the I to V converter */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0010); ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0019 | LEDC); } static void start_ci_charging(void) { rvf_send_trace("Start CI charging", 17, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_CI_CHARGING; /* Select constant current charging. The charger is disabled */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0002); /* Program the DAC with the constant current value */ ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_ctrl->config.ci_current + pwr_ctrl->i2v_offset); /* Enable the charger */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003 | LEDC); /* The total charging time starts now */ pwr_ctrl->start_time = rvf_get_tick_count(); if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGING_START); } static void start_cv_charging(void) { UINT16 code; rvf_send_trace("Start CV charging", 17, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_CV_CHARGING; /* Select constant voltage charging. The charger is disabled */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); /* figure out the DAC code */ code = madc_vbat_inverse(pwr_ctrl->config.cv_init_set); rvf_send_trace("Voltage (DAC code) ", 19, code, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); /* Program the DAC with the constant voltage value */ ABB_Write_Register_on_page(PAGE0, CHGREG, code); /* Enable the charger */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0001 | LEDC); /* CV control loop state init */ pwr_ctrl->cv_dac_init = code; pwr_ctrl->cv_dac_curr = code; pwr_ctrl->cv_high_vbat_count = 0; pwr_ctrl->cv_low_vbat_count = 0; /* Ichg averaging state init */ pwr_ctrl->ichg_fill_level = 0; pwr_ctrl->ichg_ring_ptr = 0; pwr_ctrl->ichg_low_count = 0; } static void start_charge_condition_met(void) { rvf_send_trace("Charge start condition met", 26, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); if (pwr_ctrl->config.bciconf) start_i2v_cal(); else { pwr_ctrl->i2v_offset = 0; start_ci_charging(); } } static void ci_progress_trace(UINT16 ichg) { char trace[64]; pwr_ctrl->ci_ichg = ichg; sprintf(trace, "CI charging: Vbat=%u Ichg=%u i2v=%u", pwr_ctrl->batt_mv, ichg, pwr_ctrl->i2v_offset); rvf_send_trace(trace, strlen(trace), NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); } static int cv_ichg_process(UINT16 ichg_new) { UINT16 ichg_clip, ichg_entry; UINT32 ichg_accum; UINT16 i; char trace[64]; if (pwr_ctrl->ichg_fill_level < ICHG_AVG_WINDOW) pwr_ctrl->ichg_avg_buf[pwr_ctrl->ichg_fill_level++] = ichg_new; else { ichg_clip = pwr_ctrl->ichg_average + pwr_ctrl->config.ichg_max_spike; if (ichg_new > ichg_clip) ichg_entry = ichg_clip; else ichg_entry = ichg_new; pwr_ctrl->ichg_avg_buf[pwr_ctrl->ichg_ring_ptr++] = ichg_entry; if (pwr_ctrl->ichg_ring_ptr >= ICHG_AVG_WINDOW) pwr_ctrl->ichg_ring_ptr = 0; } ichg_accum = 0; for (i = 0; i < pwr_ctrl->ichg_fill_level; i++) ichg_accum += pwr_ctrl->ichg_avg_buf[i]; pwr_ctrl->ichg_average = ichg_accum / pwr_ctrl->ichg_fill_level; sprintf(trace, "CV charging: Vbat=%u Ichg=%u Ichg_avg=%u i2v=%u", pwr_ctrl->batt_mv, ichg_new, pwr_ctrl->ichg_average, pwr_ctrl->i2v_offset); rvf_send_trace(trace, strlen(trace), NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); if (pwr_ctrl->ichg_average > (pwr_ctrl->config.end_current + pwr_ctrl->i2v_offset)) { pwr_ctrl->ichg_low_count = 0; return 0; } pwr_ctrl->ichg_low_count++; if (pwr_ctrl->ichg_low_count < pwr_ctrl->config.ichg_samples_needed) return 0; rvf_send_trace("Stopping charge by low current condition", 40, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_init_discharge(); pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE; if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGING_COMPLETE); return 1; } static int overvoltage_end_charge_check(void) { if (pwr_ctrl->batt_mv < pwr_ctrl->config.overvoltage) return 0; if (pwr_ctrl->cv_dac_curr != (pwr_ctrl->cv_dac_init - pwr_ctrl->config.cv_dac_max_decr)) return 0; rvf_send_trace("Stopping charge by overvoltage condition", 40, NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID); ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_init_discharge(); pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE; if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGING_COMPLETE); return 1; } static void cv_ctrl_loop_high_check(void) { if (pwr_ctrl->batt_mv < pwr_ctrl->config.cv_ctrl_loop_high) { pwr_ctrl->cv_high_vbat_count = 0; return; } pwr_ctrl->cv_high_vbat_count++; if (pwr_ctrl->cv_high_vbat_count < pwr_ctrl->config.cv_samples_needed) return; if (pwr_ctrl->cv_dac_curr == (pwr_ctrl->cv_dac_init - pwr_ctrl->config.cv_dac_max_decr)) return; pwr_ctrl->cv_dac_curr--; ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_ctrl->cv_dac_curr); rvf_send_trace("Sub CV DAC", 10, pwr_ctrl->cv_dac_curr, RV_TRACE_LEVEL_DEBUG_MEDIUM, FCHG_USE_ID); pwr_ctrl->cv_high_vbat_count = 0; } static void cv_ctrl_loop_low_check(void) { if (pwr_ctrl->batt_mv >= pwr_ctrl->config.cv_ctrl_loop_low) { pwr_ctrl->cv_low_vbat_count = 0; return; } pwr_ctrl->cv_low_vbat_count++; if (pwr_ctrl->cv_low_vbat_count < pwr_ctrl->config.cv_samples_needed) return; if (pwr_ctrl->cv_dac_curr == (pwr_ctrl->cv_dac_init + pwr_ctrl->config.cv_dac_max_incr)) return; pwr_ctrl->cv_dac_curr++; ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_ctrl->cv_dac_curr); rvf_send_trace("Add CV DAC", 10, pwr_ctrl->cv_dac_curr, RV_TRACE_LEVEL_DEBUG_MEDIUM, FCHG_USE_ID); pwr_ctrl->cv_low_vbat_count = 0; } static int charging_time_limit_check(void) { if ((rvf_get_tick_count() - pwr_ctrl->start_time) < RVF_SECS_TO_TICKS(pwr_ctrl->config.charge_time_limit)) return 0; rvf_send_trace("Stopping charge by time exceeded condition", 42, NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID); ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_init_discharge(); pwr_ctrl->state = FCHG_STATE_RECHARGE_TIMER; pwr_ctrl->start_time = rvf_get_tick_count(); if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGING_TIMEOUT); return 1; } void pwr_process_adc(struct pwr_adc_ind_s *msg) { pwr_ctrl->batt_mv = madc_vbat_2_physical(msg->data[0]); switch (pwr_ctrl->state) { case FCHG_STATE_NO_EXT_PWR: case FCHG_STATE_PWR_PLUG_TIMER: case FCHG_STATE_NO_CHARGING: handle_discharge(); return; case FCHG_STATE_READY_TO_CHARGE: handle_discharge(); if (!(msg->data[9] & CHGPRES)) { pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; return; } if (pwr_ctrl->batt_mv < pwr_ctrl->config.start_thresh) start_charge_condition_met(); return; case FCHG_STATE_READY_TO_RECHARGE: handle_discharge(); if (!(msg->data[9] & CHGPRES)) { pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; return; } if (pwr_ctrl->batt_mv < pwr_ctrl->config.restart_thresh) start_charge_condition_met(); return; case FCHG_STATE_I2V_CAL_1: if (!(msg->data[9] & CHGPRES)) { pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; return; } if (pwr_ctrl->config.bciconf) start_i2v_cal(); else { pwr_ctrl->i2v_offset = 0; start_ci_charging(); } return; case FCHG_STATE_I2V_CAL_2: pwr_ctrl->i2v_offset = msg->data[2]; ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); rvf_send_trace("i2v offset (MADC code) ", 23, pwr_ctrl->i2v_offset, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); if (!(msg->data[9] & CHGPRES)) { pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; pwr_init_discharge(); return; } start_ci_charging(); return; case FCHG_STATE_CI_CHARGING: ci_progress_trace(msg->data[2]); if (!(msg->data[9] & CHGPRES)) { ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; pwr_init_discharge(); return; } if (charging_time_limit_check()) return; if (pwr_ctrl->batt_mv >= pwr_ctrl->config.ci2cv_thresh) start_cv_charging(); return; case FCHG_STATE_CV_CHARGING: if (!(msg->data[9] & CHGPRES)) { ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; pwr_init_discharge(); return; } if (cv_ichg_process(msg->data[2])) return; if (overvoltage_end_charge_check()) return; if (charging_time_limit_check()) return; cv_ctrl_loop_high_check(); cv_ctrl_loop_low_check(); return; case FCHG_STATE_RECHARGE_TIMER: handle_discharge(); if ((rvf_get_tick_count() - pwr_ctrl->start_time) < RVF_SECS_TO_TICKS(pwr_ctrl->config.recharge_delay)) return; rvf_send_trace("Restart time met, allowing new charging", 39, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE; return; default: rvf_send_trace("Invalid state in pwr_process_adc()", 32, pwr_ctrl->state, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); } } void pwr_handle_timer(void) { if (pwr_ctrl->state != FCHG_STATE_PWR_PLUG_TIMER) return; rvf_send_trace("Timer expired, ready to charge", 30, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_READY_TO_CHARGE; } void pwr_charger_plug(void) { if (pwr_ctrl->state != FCHG_STATE_NO_EXT_PWR) { rvf_send_trace("Charger plug event in unexpected state", 38, pwr_ctrl->state, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); return; } if (!pwr_ctrl->config_present) { rvf_send_trace( "Charger plugged in, but no config: won't charge", 47, NULL_PARAM, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_NO_CHARGING; return; } if (pwr_ctrl->config.start_delay) { rvf_send_trace("Charger plug, starting timer", 28, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); rvf_start_timer(FCHG_TIMER, RVF_MS_TO_TICKS(pwr_ctrl->config.start_delay), FALSE); pwr_ctrl->state = FCHG_STATE_PWR_PLUG_TIMER; } else { rvf_send_trace("Charger plug, ready to charge", 29, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_READY_TO_CHARGE; } if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGER_PLUG); } void pwr_charger_unplug(void) { switch (pwr_ctrl->state) { case FCHG_STATE_NO_EXT_PWR: rvf_send_trace("Charger unplug, already handled", 31, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); /* nothing to do */ break; case FCHG_STATE_PWR_PLUG_TIMER: case FCHG_STATE_READY_TO_CHARGE: case FCHG_STATE_READY_TO_RECHARGE: case FCHG_STATE_I2V_CAL_1: case FCHG_STATE_RECHARGE_TIMER: case FCHG_STATE_NO_CHARGING: rvf_send_trace("Charger unplug", 14, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; break; case FCHG_STATE_I2V_CAL_2: case FCHG_STATE_CI_CHARGING: case FCHG_STATE_CV_CHARGING: ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); rvf_send_trace("Charger unplug, charging stopped", 32, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR; pwr_init_discharge(); break; default: rvf_send_trace("Invalid state in pwr_charger_unplug()", 35, pwr_ctrl->state, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); } if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGER_UNPLUG); } void pwr_charge_start_req(void) { switch (pwr_ctrl->state) { case FCHG_STATE_NO_EXT_PWR: rvf_send_trace("Cannot charge without a power source", 36, NULL_PARAM, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); return; case FCHG_STATE_NO_CHARGING: if (!pwr_ctrl->config_present) { rvf_send_trace("No config set, cannot charge", 28, NULL_PARAM, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); return; } /* FALL THRU */ case FCHG_STATE_PWR_PLUG_TIMER: case FCHG_STATE_READY_TO_CHARGE: case FCHG_STATE_READY_TO_RECHARGE: case FCHG_STATE_RECHARGE_TIMER: rvf_send_trace("Starting charge on user request", 31, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_I2V_CAL_1; return; case FCHG_STATE_I2V_CAL_1: case FCHG_STATE_I2V_CAL_2: case FCHG_STATE_CI_CHARGING: case FCHG_STATE_CV_CHARGING: rvf_send_trace( "Charging already in progress, start request ignored", 51, NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID); return; default: rvf_send_trace("Invalid state in pwr_charge_start_req()", 37, pwr_ctrl->state, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); } } void pwr_charge_stop_req(void) { switch (pwr_ctrl->state) { case FCHG_STATE_NO_EXT_PWR: case FCHG_STATE_NO_CHARGING: /* nothing to do */ return; case FCHG_STATE_PWR_PLUG_TIMER: case FCHG_STATE_READY_TO_CHARGE: case FCHG_STATE_READY_TO_RECHARGE: case FCHG_STATE_I2V_CAL_1: case FCHG_STATE_RECHARGE_TIMER: rvf_send_trace("Charging disabled by user request", 33, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_NO_CHARGING; return; case FCHG_STATE_I2V_CAL_2: case FCHG_STATE_CI_CHARGING: case FCHG_STATE_CV_CHARGING: ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); rvf_send_trace("Charging stopped by user request", 32, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID); pwr_ctrl->state = FCHG_STATE_NO_CHARGING; pwr_init_discharge(); if (pwr_ctrl->event_handler) pwr_ctrl->event_handler(FCHG_EVENT_CHARGING_STOPPED); return; default: rvf_send_trace("Invalid state in pwr_charge_stop_req()", 36, pwr_ctrl->state, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID); } }
