FreeCalypso > hg > fc-tourmaline
view src/cs/drivers/drv_app/lcc/lcc_task.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
/****************************************************************************** * Power Task (pwr) * Design and coding by Svend Kristian Lindholm, skl@ti.com * * Main PWR Task * * $Id: pwr_task.c 1.1 Wed, 20 Aug 2003 10:22:37 +0200 skl $ * ******************************************************************************/ #include "lcc/lcc.h" #include "lcc/lcc_task.h" #include "lcc/lcc_handle_message.h" #include "lcc/lcc_tm_i.h" #include "lcc/lcc_trace.h" #include "rv/rv_defined_swe.h" #include "ffs/ffs.h" #include <string.h> /****************************************************************************** * Globals and function prototypes ******************************************************************************/ extern T_PWR_CTRL_BLOCK *pwr_ctrl; extern T_PWR_CFG_BLOCK *pwr_cfg; // Event handling functions T_RV_RET process_spi_adc_indication (T_PWR_REQ *request); // Timer event handling functions T_RV_RET process_pwr_handle_T1_expiration (T_PWR_REQ *request); T_RV_RET process_pwr_handle_T2_expiration (T_PWR_REQ *request); T_RV_RET process_pwr_handle_T3_expiration (T_PWR_REQ *request); T_RV_RET process_pwr_handle_T4_expiration (T_PWR_REQ *request); T_RV_RET process_pwr_handle_mod_cycle_expiration(T_PWR_REQ *request); T_RV_RET process_pwr_handle_mmi_info_expiration (T_PWR_REQ *request); // Interrupt event handling functions T_RV_RET process_abb_chg_unplugged_ind (T_PWR_REQ *request); T_RVM_RETURN pwr_check_files(void); T_RVM_RETURN pwr_read_files(void); T_RVM_RETURN pwr_read_chg_files(void); T_RVM_RETURN pwr_read_cal_files(void); void build_name(const char *ch_pre, char *cfg_id , UINT8 index, const char * ch_post, char * name); // FFS function prototypes effs_t ffs_stat(const char *name, struct stat_s *stat); int ffs_fread(const char *name, void *addr, int size); void ttr(unsigned trmask, char *format, ...); void str(unsigned mask, char *string); /****************************************************************************** * PWR Task ******************************************************************************/ // This function checks the existance of FFS directories and files related // to the PWR module - See RD818 // If the existance of the object is MANDATORY pwr_check_files returns an // error and the PWR configuration is stopped // If the existance of the object is OPTIONAL pwr_check_files a // warning is given and the PWR configuration proceeds T_RVM_RETURN pwr_check_files() { T_FFS_SIZE error; T_FFS_STAT stat; ttw(ttr(TTrInit, "pwr_check_files(%d)" NL, 0)); // Check directories: // /pwr MANDATORY // /pwr/bat MANDATORY // /pwr/chg OPTIONAL // /mmi OPTIONAL // /mmi/pwr OPTIONAL // MANDATORY directories if ((error = ffs_stat("/pwr", &stat)) == EFFS_OK) { if (stat.type != OT_DIR) { ttr(TTrFatal, "pwr exists but is not a directory %d" NL, 0); return EFFS_NOTADIR; } } else { ttr(TTrFatal, "no /pwr directory %d" NL, 0); return error; } if ((error = ffs_stat("/pwr/bat", &stat)) == EFFS_OK) { if (stat.type != OT_DIR) { ttr(TTrFatal, "/pwr/bat exists but is not a directory %d" NL, 0); return EFFS_NOTADIR; } } else { ttr(TTrFatal, "no /pwr/bat directory %d" NL, 0); return error; } // OPTIONAL directories if ((error = ffs_stat("/pwr/chg", &stat)) == EFFS_OK) { if (stat.type != OT_DIR) { ttr(TTrWarning, "/pwr/chg exists but is not a directory %d" NL, 0); } } else { ttr(TTrWarning, "no /pwr/chg directory %d" NL, 0); } if ((error = ffs_stat("/mmi", &stat)) == EFFS_OK) { if (stat.type != OT_DIR) { ttr(TTrWarning, "/mmi exists but is not a directory %d" NL, 0); } } else { ttr(TTrWarning, "no /mmi directory %d" NL, 0); } if ((error = ffs_stat("/mmi/pwr", &stat)) == EFFS_OK) { if (stat.type != OT_DIR) { ttr(TTrWarning, "/mmi/pwr exists but is not a directory %d" NL, 0); } } else { ttr(TTrWarning, "no /mmi/pwr directory %d" NL, 0); } // Check calibration files: // /pwr/vbat.cal MANDATORY // NOT checked - it MUST be present - else we will have no Vbat measurements // Check configuration files: // /pwr/common.cfg MANDATORY // /pwr/bat/bat<N>.cfg MANDATORY // /pwr/bat/temp<N>.cfg OPTIONAL // /pwr/chg/chg<N>.cfg OPTIONAL // MANDATORY files if ((error = ffs_stat("/pwr/common.cfg", &stat)) == EFFS_OK) { if (stat.type != OT_FILE) { ttr(TTrFatal, "/pwr/common.cfg exists but is not a file %d" NL, 0); return EFFS_NOTADIR; } } else { ttr(TTrFatal, "no /pwr/common.cfg file %d" NL, 0); return error; } ttw(ttr(TTrInit, "pwr_check_files(%d)" NL, 0xFF)); return RV_OK; } // This function reads the FFS pwr configuration files // /pwr/vbat.cal MANDATORY // /mmi/pwr/bsie OPTIONAL // /pwr/common.cfg MANDATORY // /pwr/bat/bat<n>.cfg MANDATORY // /pwr/bat/temp<n>.cfg MANDATORY // // Precondition: Files have been checked with pwr_check_files() // Therefore we know they exist. Charger files are read later. // T_RVM_RETURN pwr_read_files() { T_FFS_SIZE error; T_FFS_STAT stat; char name[20]; uint8 i; char cfg_id; ttw(ttr(TTrInit, "pwr_read_files(%d)" NL, 0)); // Brute force of charger configuration ? /pwr/chg/force if ((error = ffs_stat("/pwr/chg/force", &stat)) == EFFS_OK) { error = ffs_fread("/pwr/chg/force", &pwr_cfg->data.cforce, 1); ttw(ttr(TTrInitLow, "Read /pwr/chg/force(%d)" NL, error)); pwr_cfg->data.chg_cfg_id = pwr_cfg->data.cforce + '0'; pwr_ctrl->chg_cfg_id = pwr_cfg->data.cforce; } else { // Use 'normal' 'plug & play' configuration pwr_cfg->data.cforce = 0; pwr_cfg->data.chg_cfg_id = 1 + '0'; // Default pwr_ctrl->chg_cfg_id = 1; // Default } // Brute force of battery configuration ? /pwr/bat/force if ((error = ffs_stat("/pwr/bat/force", &stat)) == EFFS_OK) { error = ffs_fread("/pwr/bat/force", &pwr_cfg->data.bforce, 1); ttw(ttr(TTrInitLow, "Read /pwr/bat/force(%d)" NL, error)); pwr_ctrl->cfg_id = pwr_cfg->data.bforce; pwr_cfg->data.cfg_id = pwr_cfg->data.bforce + '0'; } else { // Use 'normal' 'plug & play' configuration // Precondition: We have a reliable battery id measurement pwr_cfg->data.bforce = 0; ttw(ttr(TTrInitLow, "Plug & play bat_id=%d" NL, pwr_cfg->data.bat_id)); } // Read /pwr/common.cfg error = ffs_fread("/pwr/common.cfg", &pwr_cfg->common, PWR_COMMON_CFG_SIZE); ttw(ttr(TTrInitLow, "Read /pwr/common.cfg(%d)" NL, error)); // Read /mmi/pwr/bsie // Apply defaults if file doesn't exist if ((error = ffs_stat("/mmi/pwr/bsie.cfg", &stat)) == EFFS_OK) { if (stat.type != OT_FILE) { ttr(TTrWarning, "/mmi/pwr/bsie.cfg exists but is not a file %d" NL, 0); return EFFS_NOTAFILE; } else { error = ffs_fread("/mmi/pwr/bsie.cfg", &pwr_cfg->mmi, sizeof(pwr_cfg->mmi)); ttw(ttr(TTrInitLow, "Read /mmi/pwr/bsie.cfg(%d)" NL, error)); } } else { ttr(TTrWarning, "no /mmi/pwr/bsie file %d" NL, 0); // Apply defaults pwr_cfg->mmi.repetition = PWR_MMI_REP_THR; } if (pwr_cfg->data.bforce > 0) { // Brute force battery configuration build_name("/pwr/bat/bat", &pwr_cfg->data.cfg_id, 12, ".cfg", name); error = ffs_fread(name, &pwr_cfg->bat, PWR_BAT_CFG_SIZE); build_name("/pwr/bat/temp", &pwr_cfg->data.cfg_id, 13, ".cfg", name); error = ffs_fread(name, &pwr_cfg->temp, PWR_TEMP_CFG_SIZE); } else { // Find out which <n> and read /pwr/bat/bat<n>.cfg // We know that at least one battery configuration file exists // Pick the file that matches the bat_id measured earlier for (i = 1; i <= 5; i++) { cfg_id = i + '0'; build_name("/pwr/bat/bat", &cfg_id, 12, ".cfg", name); error = ffs_fread(name, &pwr_cfg->bat, PWR_BAT_CFG_SIZE); // Found the right battery id?? if ((pwr_cfg->data.bat_id >= pwr_cfg->bat.id_low) && (pwr_cfg->data.bat_id <= pwr_cfg->bat.id_high)) { ttw(ttr(TTrInitLow, "Chose %s" NL, name)); // Save the configuration number in the name pwr_ctrl->cfg_id = i; pwr_cfg->data.cfg_id = cfg_id; pwr_ctrl->flag_bat_unknown = 0; // Read the corresponding temperature configuration build_name("/pwr/bat/temp", &pwr_cfg->data.cfg_id, 13, ".cfg", name); error = ffs_fread(name, &pwr_cfg->temp, PWR_TEMP_CFG_SIZE); break; } } // Check if a matching battery configuration was found if ((pwr_cfg->data.cfg_id < '1') || (pwr_cfg->data.cfg_id > '5')) { pwr_cfg->data.cfg_id = '1'; pwr_ctrl->cfg_id = 1; ttr(TTrWarning, "No matching battery configuration id - Defaults to %d" NL, pwr_ctrl->cfg_id); // Flag that battery configuration was unknown // Inform the MMI later when it has registered pwr_ctrl->flag_bat_unknown = 1; } } ttw(ttr(TTrInit, "pwr_read_files(%d)" NL, 0xFF)); return RV_OK; } // Read calibration files only T_RVM_RETURN pwr_read_cal_files() { T_FFS_SIZE error; // Read /pwr/vbat.cal error = ffs_fread("/pwr/vbat.cal", &pwr_cfg->cal.vbat, sizeof(pwr_cfg->cal.vbat)); if ( error < EFFS_OK ) return RVM_INTERNAL_ERR; ttw(ttr(TTrInitLow, "Read /pwr/vbat.cal(%d)" NL, error)); ttw(ttr(TTrInitLow, "pwr_cfg->cal.vbat.alfa_num=%d" NL, pwr_cfg->cal.vbat.alfa_num)); ttw(ttr(TTrInitLow, "pwr_cfg->cal.vbat.alfa_denom=%d" NL, pwr_cfg->cal.vbat.alfa_denom)); ttw(ttr(TTrInitLow, "pwr_cfg->cal.vbat.beta=%d" NL, pwr_cfg->cal.vbat.beta)); return RVM_OK; } // This function reads the FFS pwr configuration file // It is invoked when a charger is plugged // /pwr/chg/chg<n>.cfg MANDATORY T_RVM_RETURN pwr_read_chg_files() { T_FFS_SIZE error; char name[20]; uint8 i; char chg_id; ttw(ttr(TTrInit, "pwr_read_chg_files(%d)" NL, 0)); if (pwr_cfg->data.cforce > 0) { // Brute force charger configuration build_name("/pwr/chg/chg", &pwr_cfg->data.chg_cfg_id, 12, ".cfg", name); error = ffs_fread(name, &pwr_cfg->chg, PWR_CHG_CFG_SIZE); ttw(ttr(TTrInitLow,"error = %d" NL, error)); // Readout /pwr/chg/chg<N>.cfg ttw(ttr(TTrInitLow,"chg.cfg: type: %d" NL, pwr_cfg->chg.type)); ttw(ttr(TTrInitLow,"ichg_max: %d" NL, pwr_cfg->chg.ichg_max)); ttw(ttr(TTrInitLow,"vchg_low: %d" NL, pwr_cfg->chg.vchg_low)); ttw(ttr(TTrInitLow,"vchg_high: %d" NL, pwr_cfg->chg.vchg_high)); } else { // Find out which <n> and read /pwr/chg/chg<n>.cfg // We know that at least one charger configuration file exists // Pick the file that matches the chg_id measured earlier for (i = 1; i <= 5; i++) { chg_id = i + '0'; build_name("/pwr/chg/chg", &chg_id, 12, ".cfg", name); error = ffs_fread(name, &pwr_cfg->chg, PWR_CHG_CFG_SIZE); ttw(ttr(TTrInitLow,"error = %d" NL, error)); // Readout /pwr/chg/chg<N>.cfg ttw(ttr(TTrInitLow,"chg.cfg: type: %d" NL, pwr_cfg->chg.type)); ttw(ttr(TTrInitLow,"ichg_max: %d" NL, pwr_cfg->chg.ichg_max)); ttw(ttr(TTrInitLow,"vchg_low: %d" NL, pwr_cfg->chg.vchg_low)); ttw(ttr(TTrInitLow,"vchg_high: %d" NL, pwr_cfg->chg.vchg_high)); // Found the right charger id?? if ((pwr_cfg->data.chg_id > pwr_cfg->chg.vchg_low) && (pwr_cfg->data.chg_id < pwr_cfg->chg.vchg_high)) { ttw(ttr(TTrInitLow, "Chose %s" NL, name)); // Save the configuration number in the name pwr_ctrl->chg_cfg_id = i; pwr_cfg->data.chg_cfg_id = chg_id; pwr_ctrl->flag_chg_unknown = 0; break; } } // Check if a matching charger configuration was found if ((pwr_cfg->data.chg_cfg_id < '1') || (pwr_cfg->data.chg_cfg_id > '5')) { pwr_cfg->data.chg_cfg_id = '1'; pwr_ctrl->chg_cfg_id = 1; ttr(TTrWarning, "No matching charger configuration id - Defaults to %d" NL, pwr_ctrl->chg_cfg_id); // Flag that charger configuration was unknown // Inform the MMI later when it has registered pwr_ctrl->flag_chg_unknown = 1; } } ttw(ttr(TTrInit, "pwr_read_chg_files(%d)" NL, 0xFF)); } void *pwr_malloc(int size) { void *addr; if (rvf_get_buf(pwr_ctrl->prim_id, size, &addr) == RVF_RED) { ttr(TTrFatal, "PWR FATAL: No Memory (%d)" NL, pwr_ctrl->state); return NULL; } return addr; } void pwr_free(void *addr) { int error; ttw(ttr(TTrEvent, "pwr_free (%d)" NL, 0)); if ((error = rvf_free_buf(addr)) != RV_OK) { ttr(TTrFatal, "PWR FATAL: pwr_free (%d)" NL, error); } } void pwr_task() { void *request; struct pwr_req_s *pwr_request; int error; ttw(ttr(TTrEnv, "pwr_task(%d)" NL, 0)); while (1) { rvf_wait(RVF_TASK_MBOX_0_EVT_MASK,0); request = rvf_read_mbox(RVF_TASK_MBOX_0); pwr_request = (struct pwr_req_s *)request; if (request != NULL) { ttw(ttr(TTrEvent, "Received Event(%d)" NL, pwr_request->header.msg_id)); ttw(ttr(TTrEventLow, "src_addr_id(%d)" NL, pwr_request->header.src_addr_id)); ttw(ttr(TTrEventLow, "dest_addr_id(%d)" NL, pwr_request->header.dest_addr_id)); switch (pwr_request->header.msg_id) { case PWR_CHARGER_PLUGGED_IND: // Sometimes (low voltage - init) receiving a ghost charger plug although interrupts are disabled pwr_free(request); break; case PWR_CHARGER_UNPLUGGED_IND: error = process_abb_chg_unplugged_ind(pwr_request); break; case PWR_ADC_IND : error = process_spi_adc_indication(request); break; // Timers case TIMER_T1_EXPIRED: error = process_pwr_handle_T1_expiration(request); break; case TIMER_T2_EXPIRED: error = process_pwr_handle_T2_expiration(request); break; case TIMER_T3_EXPIRED: error = process_pwr_handle_T3_expiration(request); break; case TIMER_T4_EXPIRED: error = process_pwr_handle_T4_expiration(request); break; case TIMER_MOD_CYCLE_EXPIRED: error = process_pwr_handle_mod_cycle_expiration(request); break; case TIMER_MMI_INFO_EXPIRED: error = process_pwr_handle_mmi_info_expiration(request); break; default : { ttr(TTrFatal, "PWR FATAL: Unknown Event: %d" NL, pwr_request->header.msg_id); ttr(TTrFatal, " State: %d" NL, pwr_ctrl->state); // Exception Handling - Unknown Event } } } else { // Exception Handling - NULL pointer ttr(TTrFatal, "PWR FATAL: NULL pointer (%d)" NL, pwr_ctrl->state); } } ttw(ttr(TTrEnv, "pwr_task(%d)" NL, 0xFF)); }