FreeCalypso > hg > fc-tourmaline
view src/cs/drivers/drv_app/pwr/pwr_liion_cha.c @ 281:a75eefbf8be4
Phone boot with PWON: weed out short button presses
Every standard end user phone has a design provision, most naturally
implemented in firmware, whereby the PWON button effects a boot only
if it is held down long enough - short presses of this PWON button
are detected, assumed to be spurious and cause the fw to power back off
instead of proceeding with boot. The present change introduces this
standard function in FreeCalypso.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 24 Sep 2021 02:03:08 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/******************************************************************************* * * pwr_liion_cha.c * * Purpose: This file contains functions for managing the Li-ion batteries * charging process. * * Author Candice Bazanegue (c-brille@ti.com) * * * (C) Texas Instruments 2001 * ******************************************************************************/ #include "rv/rv_defined_swe.h" // for RVM_PWR_SWE #ifdef RVM_PWR_SWE #include "rvm/rvm_use_id_list.h" #include "spi/spi_task.h" #include "spi/spi_api.h" #include "pwr/pwr_cust.h" #include "pwr/pwr_liion_cha.h" #include "pwr/pwr_disch.h" #include "spi/spi_env.h" #include "rvf/rvf_api.h" #include "pwr/pwr_analog_dev.h" #include "pwr/pwr_messages.h" /* Global variable */ extern T_SPI_GBL_INFO *SPI_GBL_INFO_PTR; /******************************************************************************* ** Function pwr_start_CI_charging ** ** Description This function is used to start the constant current ** battery charging. ** *******************************************************************************/ void pwr_start_CI_charging(unsigned short charging_current) { volatile unsigned short dac_current_code; rvf_send_trace("Start CI charging",17, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); dac_current_code = (unsigned int)((1000 * charging_current)/DAC_CURRENT_STEP); /* 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, dac_current_code); /* Enable the charger */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003); pwr_env_ctrl_blk->charging_state = CI_CHARGE_STARTED; } /******************************************************************************* ** Function pwr_start_CV_charging ** ** Description This function is used to start the constant voltage ** battery charging. ** *******************************************************************************/ void pwr_start_CV_charging(unsigned short charging_voltage) { volatile unsigned short dac_voltage_code; unsigned short dac_voltage; rvf_send_trace("Start CV charging",17, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); dac_voltage = charging_voltage + VOLTAGE_LOOP_OFFSET; dac_voltage_code = (unsigned int)((1000 * ((dac_voltage /4) - DAC_THRESHOLD))/DAC_VOLTAGE_STEP); rvf_send_trace("Voltage (DAC code) ", 19, dac_voltage_code, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); /* Select constant voltage charging. The charger is disabled */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); /* Program the DAC with the constant voltage value */ ABB_Write_Register_on_page(PAGE0, CHGREG, dac_voltage_code); /* Enable the charger */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0001); pwr_env_ctrl_blk->charging_state = CV_CHARGE_STARTED; } /******************************************************************************* ** Function pwr_stop_charging ** ** Description This function is used to stop the battery charging process. ** *******************************************************************************/ void pwr_stop_charging(void) { rvf_send_trace("Stop charging process",21, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_env_ctrl_blk->charging_state = CHARGE_STOPPED; } /******************************************************************************* ** Function pwr_current_loop_cal ** ** Description This function is used to evaluate the offset introduced ** by the current to voltage converter in the current loop. ** ** *******************************************************************************/ void pwr_current_loop_cal(void) { rvf_send_trace("Current loop calibration",24, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); /* 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); if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* start ICHG channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, ICHGREG, 0x0000); rvf_start_timer (SPI_TIMER0, RVF_MS_TO_TICKS (SPI_TIMER0_INTERVAL_3), FALSE); } else /* The L1 asks for ADC conversions */ { rvf_start_timer (SPI_TIMER0, RVF_MS_TO_TICKS (SPI_TIMER0_INTERVAL_4), FALSE); } } /******************************************************************************* ** Function pwr_calibration_process ** ** Description ** *******************************************************************************/ void pwr_calibration_process(void) { if (pwr_bat_temp_within_limits(pwr_env_ctrl_blk->bat_celsius_temp)) { pwr_env_ctrl_blk->timer0_state = BATTERY_CALIBRATION; pwr_current_loop_cal(); } else { /* informs the upper layer that the battery temperature is not correct */ pwr_send_charge_not_possible_event(BAT_TEMP_OUTSIDE_LIMITS); if (SPI_GBL_INFO_PTR->is_gsm_on == FALSE) /* GSM OFF */ { #if (ANLG_FAM == 1) ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE); #elif (ANLG_FAM == 2) ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001); #endif } else { pwr_handle_discharge(); } } } /******************************************************************************* ** Function pwr_battery_qualification ** ** Description Battery open and short tests ** *******************************************************************************/ void pwr_battery_qualification(void) { rvf_send_trace("Battery qualification",21, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); pwr_env_ctrl_blk->timer0_state = BATTERY_SHORT_TEST; /* Short test */ pwr_start_CI_charging(CONSTANT_CURRENT_VALUE); if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* Start VBAT channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, VBATREG, 0x0000); rvf_start_timer (SPI_TIMER0, RVF_MS_TO_TICKS (SPI_TIMER0_INTERVAL_1), FALSE); } else { /* Let time for the L1 to ask for new AD conversions */ rvf_start_timer (SPI_TIMER0, RVF_MS_TO_TICKS (SPI_TIMER0_INTERVAL_2), FALSE); } } /********************************************************************************/ /* */ /* Function Name: pwr_start_fast_charge */ /* */ /* Purpose: Starts the fast charging process for Li-ion batteries */ /* */ /* */ /********************************************************************************/ void pwr_start_fast_charge(void) { UINT16 i2v_dac_offset_mA; /* Informs the upper layer that the charging process has started */ pwr_send_CI_charge_start_event(); /* Connect resistive bridge to main battery */ ABB_Write_Register_on_page(PAGE0, BCICTL1, MESBAT); /* Start the constant current charging */ i2v_dac_offset_mA = (UINT16)((MADC_CURRENT_STEP*pwr_env_ctrl_blk->i2v_madc_offset)/1000); pwr_start_CI_charging((unsigned short)(CONSTANT_CURRENT_VALUE + i2v_dac_offset_mA)); rvf_start_timer (SPI_TIMER1, RVF_MS_TO_TICKS (SPI_TIMER1_INTERVAL), FALSE); } /********************************************************************************/ /* */ /* Function Name: pwr_short_test_timer_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_short_test_timer_process(void) { UINT16 Vbat_test; rvf_send_trace("TIMER0: Battery short test",26, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); /* Read ADC result */ Vbat_test = ABB_Read_Register_on_page(PAGE0, VBATREG); rvf_send_trace("Vbat (MADC code) ",17, Vbat_test, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); pwr_stop_charging(); if (Vbat_test > 0) { pwr_env_ctrl_blk->timer0_state = BATTERY_OPEN_TEST; /* Start open test */ pwr_start_CV_charging(CONSTANT_VOLTAGE_VALUE); rvf_delay(RVF_MS_TO_TICKS(5)); if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* start ICHG channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, ICHGREG, 0x0000); rvf_start_timer (SPI_TIMER0, RVF_MS_TO_TICKS (SPI_TIMER0_INTERVAL_1), FALSE); } else { /* Let time for the L1 to ask for new AD conversions */ rvf_start_timer (SPI_TIMER0, RVF_MS_TO_TICKS (SPI_TIMER0_INTERVAL_2), FALSE); } } else { rvf_send_trace("Short battery",13, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); /* informs the upper layer that the short test has failed */ pwr_send_charge_not_possible_event(BAT_SHORT_TEST_FAILED); if (SPI_GBL_INFO_PTR->is_gsm_on == FALSE) /* GSM OFF */ { #if (ANLG_FAM == 1) ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE); #elif (ANLG_FAM == 2) ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001); #endif } else { pwr_handle_discharge(); } } } /********************************************************************************/ /* */ /* Function Name: pwr_open_test_timer_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_open_test_timer_process(void) { UINT16 Ichg_test; rvf_send_trace("TIMER0: Battery open test",25, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); /* Read ADC result */ Ichg_test = ABB_Read_Register_on_page(PAGE0, ICHGREG); rvf_send_trace("Charge current (MADC code) ",27, Ichg_test, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); pwr_stop_charging(); if (Ichg_test > 0) /* Battery OK */ { rvf_send_trace("Battery OK",10, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); /* Check if the initial battery temperature is correct */ pwr_env_ctrl_blk->charging_state = TESTING_BATTERY; pwr_get_battery_temperature(); } else /* Open battery */ { rvf_send_trace("Open battery",12, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); /* informs the upper layer that the open test has failed */ pwr_send_charge_not_possible_event(BAT_OPEN_TEST_FAILED); if (SPI_GBL_INFO_PTR->is_gsm_on == FALSE) /* GSM OFF */ { #if (ANLG_FAM == 1) ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE); #elif (ANLG_FAM == 2) ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001); #endif } else { pwr_handle_discharge(); } } } /********************************************************************************/ /* */ /* Function Name: pwr_cal_timer_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_cal_timer_process(void) { rvf_send_trace("TIMER0: Battery calibration",27, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); pwr_env_ctrl_blk->i2v_madc_offset = ABB_Read_Register_on_page(PAGE0, ICHGREG); rvf_send_trace("i2v offset (MADC code) ", 23, pwr_env_ctrl_blk->i2v_madc_offset, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); pwr_stop_charging(); #if (ANLG_FAM == 2) if (pwr_env_ctrl_blk->i2v_madc_offset == 0) { /* IOTA: the offset can be made positive and minimized programming */ /* the OFFEN and OFFSN bits in the BCICONF register */ ABB_Write_Register_on_page(PAGE1, BCICONF, 0x001F); pwr_current_loop_cal(); } else { /* the i2v calibration must be done before this initialization */ pwr_env_ctrl_blk->madc_eoc_current_code = (UINT16)(1000 * END_OF_CHARGE_I / MADC_CURRENT_STEP) + pwr_env_ctrl_blk->i2v_madc_offset; rvf_send_trace("End of charge current (MADC code) ", 34, pwr_env_ctrl_blk->madc_eoc_current_code, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); /* Start the fast charging cycle */ pwr_start_fast_charge(); } #elif (ANLG_FAM == 1) /* the i2v calibration must be done before this initialization */ pwr_env_ctrl_blk->madc_eoc_current_code = (UINT16)(1000 * END_OF_CHARGE_I / MADC_CURRENT_STEP) + pwr_env_ctrl_blk->i2v_madc_offset; rvf_send_trace("End of charge current (MADC code) ", 34, pwr_env_ctrl_blk->madc_eoc_current_code, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); /* Start the fast charging cycle */ pwr_start_fast_charge(); #endif /* #if (ANLG_FAM == 2) */ } /********************************************************************************/ /* */ /* Function Name: pwr_CI_charge_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_CI_charge_process(void) { UINT16 vbat; UINT16 ichg; /* Check if the battery temperature is still correct */ if (pwr_bat_temp_within_limits(pwr_env_ctrl_blk->bat_celsius_temp)) { if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* start VBAT channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, VBATREG, 0x0000); rvf_delay(RVF_MS_TO_TICKS(5)); vbat = ABB_Read_Register_on_page(PAGE0, VBATREG); } else { /* Use the ADC conversions results from the L1 */ vbat = SPI_GBL_INFO_PTR->adc_result[0]; } rvf_send_trace("TIMER1", 6, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); rvf_send_trace("Vbat (MADC code) ", 17, vbat, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); if (vbat < pwr_env_ctrl_blk->max_voltage_code) { rvf_start_timer (SPI_TIMER1, RVF_MS_TO_TICKS (SPI_TIMER1_INTERVAL), FALSE); } else { pwr_stop_charging(); pwr_send_CV_charge_start_event(); pwr_start_CV_charging(CONSTANT_VOLTAGE_VALUE); rvf_start_timer (SPI_TIMER2, RVF_MS_TO_TICKS (SPI_TIMER2_INTERVAL), FALSE); } if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* start ICHG channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, ICHGREG, 0x0000); rvf_delay(RVF_MS_TO_TICKS(5)); ichg = ABB_Read_Register_on_page(PAGE0, ICHGREG); } else { ichg = SPI_GBL_INFO_PTR->adc_result[2]; } rvf_send_trace("Ichg (MADC code) ", 17, ichg, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); } else /* battery temperature not correct !!! */ { pwr_stop_charging(); rvf_send_trace("Battery temperature not correct! ",33, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); /* informs the upper layer that the battery temperature is not correct */ pwr_send_charge_not_possible_event(BAT_TEMP_OUTSIDE_LIMITS); if (SPI_GBL_INFO_PTR->is_gsm_on == FALSE) /* GSM OFF */ { #if (ANLG_FAM == 1) ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE); #elif (ANLG_FAM == 2) ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001); #endif } else { pwr_handle_discharge(); } } } /********************************************************************************/ /* */ /* Function Name: pwr_CI_charge_timer_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_CI_charge_timer_process(void) { UINT16 status_value; status_value = ABB_Read_Status(); if (status_value & CHGPRES) /* if the charger is still plugged */ { pwr_get_battery_temperature(); } else { /* informs the upper layer that the charging process has stopped */ pwr_send_charge_stop_event(); } } /********************************************************************************/ /* */ /* Function Name: pwr_CV_charge_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_CV_charge_process(void) { UINT16 vbat; UINT16 ichg; /* Check if the battery temperature is still correct */ if (pwr_bat_temp_within_limits(pwr_env_ctrl_blk->bat_celsius_temp)) { if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* start ICHG channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, ICHGREG, 0x0000); rvf_delay(RVF_MS_TO_TICKS(5)); ichg = ABB_Read_Register_on_page(PAGE0, ICHGREG); } else { ichg = SPI_GBL_INFO_PTR->adc_result[2]; } rvf_send_trace("TIMER2",6, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); rvf_send_trace("Ichg (MADC code) ", 17, ichg, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); if (SPI_GBL_INFO_PTR->is_adc_on == FALSE) { /* start VBAT channel conversion by writing in the result register */ ABB_Write_Register_on_page(PAGE0, VBATREG, 0x0000); rvf_delay(RVF_MS_TO_TICKS(5)); vbat = ABB_Read_Register_on_page(PAGE0, VBATREG); } else { /* Use the ADC results asked for by the layer 1 */ vbat = SPI_GBL_INFO_PTR->adc_result[0]; } rvf_send_trace("Vbat (MADC code) ", 17, vbat, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); if (ichg > pwr_env_ctrl_blk->madc_eoc_current_code) { rvf_start_timer (SPI_TIMER2, RVF_MS_TO_TICKS (SPI_TIMER2_INTERVAL), FALSE); } else { pwr_stop_charging(); /* informs the upper layer that the charging process has stopped */ pwr_send_charge_stop_event(); rvf_send_trace("Fast charge termination criterion",33, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, PWR_USE_ID); if (SPI_GBL_INFO_PTR->is_gsm_on == FALSE) /* GSM OFF */ { #if (ANLG_FAM == 1) ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE); #elif (ANLG_FAM == 2) ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001); #endif } else { pwr_handle_discharge(); } } } else /* Battery temperature not correct !!! */ { pwr_stop_charging(); rvf_send_trace("Battery temperature not correct! ",33, NULL_PARAM, RV_TRACE_LEVEL_WARNING, PWR_USE_ID); /* informs the upper layer that the battery temperature is not correct */ pwr_send_charge_not_possible_event(BAT_TEMP_OUTSIDE_LIMITS); if (SPI_GBL_INFO_PTR->is_gsm_on == FALSE) /* GSM OFF */ { #if (ANLG_FAM == 1) ABB_Write_Register_on_page(PAGE0, VRPCCTL2, 0x00EE); #elif (ANLG_FAM == 2) ABB_Write_Register_on_page(PAGE0, VRPCDEV, 0x0001); #endif } else { pwr_handle_discharge(); } } } /********************************************************************************/ /* */ /* Function Name: pwr_CV_charge_timer_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_CV_charge_timer_process(void) { UINT16 status_value; status_value = ABB_Read_Status(); if (status_value & CHGPRES) /* if the charger is still plugged */ { /* Control the battery temperature */ pwr_get_battery_temperature(); } else { /* informs the upper layer that the charging process has stopped */ pwr_send_charge_stop_event(); } } /********************************************************************************/ /* */ /* Function Name: pwr_bat_test_timer_process */ /* */ /* Purpose: */ /* */ /* */ /********************************************************************************/ void pwr_bat_test_timer_process(void) { if (pwr_env_ctrl_blk->timer0_state == BATTERY_TYPE_TEST) { pwr_type_test_timer_process(); } else if (pwr_env_ctrl_blk->timer0_state == BATTERY_SHORT_TEST) { pwr_short_test_timer_process(); } else if (pwr_env_ctrl_blk->timer0_state == BATTERY_OPEN_TEST) { pwr_open_test_timer_process(); } else if (pwr_env_ctrl_blk->timer0_state == BATTERY_50UA_TEMP_TEST) { pwr_bat_50uA_temp_test_timer_process(); } else if (pwr_env_ctrl_blk->timer0_state == BATTERY_10UA_TEMP_TEST) { pwr_bat_10uA_temp_test_timer_process(); } else if (pwr_env_ctrl_blk->timer0_state == BATTERY_CALIBRATION) { /* end of current loop calibration */ pwr_cal_timer_process(); } } #endif /* #ifdef RVM_PWR_SWE */