static void battery_error_work(struct work_struct *work) { struct battery_info *info = container_of(work, struct battery_info, error_work); int err_cnt; int old_vcell, new_vcell, vcell_diff; pr_info("%s\n", __func__); if (info->vf_state == true) { pr_info("%s: battery error state\n", __func__); old_vcell = info->battery_vcell; new_vcell = 0; for (err_cnt = 1; err_cnt <= VF_CHECK_COUNT; err_cnt++) { #if defined(CONFIG_MACH_P11) || defined(CONFIG_MACH_P10) /* FIXME: fix P11 build error temporarily */ #else if (is_jig_attached == JIG_ON) { pr_info("%s: JIG detected, return\n", __func__); return; } #endif info->battery_present = battery_get_info(info, POWER_SUPPLY_PROP_PRESENT); if (info->battery_present == 0) { pr_info("%s: battery still error(%d)\n", __func__, err_cnt); msleep(VF_CHECK_DELAY); } else { pr_info("%s: battery detect ok, " "check soc\n", __func__); new_vcell = battery_get_info(info, POWER_SUPPLY_PROP_VOLTAGE_NOW); vcell_diff = abs(old_vcell - new_vcell); pr_info("%s: check vcell: %d -> %d, diff: %d\n", __func__, info->battery_vcell, new_vcell, vcell_diff); if (vcell_diff > RESET_SOC_DIFF_TH) { pr_info("%s: reset soc\n", __func__); battery_control_info(info, POWER_SUPPLY_PROP_CAPACITY, 1); } else pr_info("%s: keep soc\n", __func__); break; } if (err_cnt == VF_CHECK_COUNT) { pr_info("%s: battery error, power off\n", __func__); battery_charge_control(info, CHARGE_DISABLE, CHARGER_OFF_CURRENT); } } } return; }
/* Setup init condition */ static void test_setup(int on_ac) { const struct battery_info *bat_info = battery_get_info(); reset_mocks(); /* 50% of charge */ sb_write(SB_RELATIVE_STATE_OF_CHARGE, 50); sb_write(SB_ABSOLUTE_STATE_OF_CHARGE, 50); /* full charge capacity in mAh */ sb_write(SB_FULL_CHARGE_CAPACITY, 0xf000); /* 25 degree Celsius */ sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(25)); /* battery pack voltage */ sb_write(SB_VOLTAGE, bat_info->voltage_normal); /* desired charging voltage/current */ sb_write(SB_CHARGING_VOLTAGE, bat_info->voltage_max); sb_write(SB_CHARGING_CURRENT, 4000); /* battery pack current is positive when charging */ if (on_ac) { sb_write(SB_CURRENT, 1000); gpio_set_level(GPIO_AC_PRESENT, 1); } else { sb_write(SB_CURRENT, -100); gpio_set_level(GPIO_AC_PRESENT, 0); } /* Reset the charger state to initial state */ charge_control(CHARGE_CONTROL_NORMAL); /* Let things stabilize */ wait_charging_state(); }
void protocol_transmitGroup(void) { uint8_t packet[18]; int16_t value, current, voltage, binfo; int8_t checksum=0, i; value = battery_get_parameter_value(parameter); voltage = battery_get_parameter_value(TOTAL_SPANNUNG); current = battery_get_parameter_value(IST_STROM); binfo = battery_get_info(); packet[ 0] = FRAME; packet[ 1] = address; packet[ 2] = TRM_GROUP; packet[ 3] = binfo >> 8; packet[ 4] = binfo & 0xff; packet[ 5] = current >> 8; packet[ 6] = current & 0xff; packet[ 7] = voltage >> 8; packet[ 8] = voltage & 0xff; packet[ 9] = value >> 8; packet[10] = value & 0xff; for(i=2; i<=10; i++) checksum ^= packet[i]; packet[11] = checksum; length = protocol_frame_stuffing(packet, 12); uart_send_twike( packet, length); }
static bool battery_vf_cond(struct battery_info *info) { pr_debug("%s\n", __func__); #if defined(CONFIG_MACH_P11) || defined(CONFIG_MACH_P10) /* FIXME: fix P11 build error temporarily */ #else /* jig detect by MUIC */ if (is_jig_attached == JIG_ON) { pr_info("%s: JIG ON, do not check\n", __func__); info->vf_state = false; return false; } #endif /* TODO: Check VF from ADC */ /* Now, battery present from charger */ info->battery_present = battery_get_info(info, POWER_SUPPLY_PROP_PRESENT); if (info->battery_present == 0) { pr_info("%s: battery is not detected.\n", __func__); info->vf_state = true; } else { pr_debug("%s: battery is detected.\n", __func__); info->vf_state = false; } return info->vf_state; }
/** * Init state handler * * - check ac, charger, battery and temperature * - initialize charger * - new states: DISCHARGE, IDLE */ static enum charge_state state_init(struct charge_state_context *ctx) { /* Stop charger, unconditionally */ charge_request(0, 0); /* if battery was not detected initially, get battery info again */ if (ctx->battery == NULL) ctx->battery = battery_get_info(); /* Update static battery info */ update_battery_info(); /* Clear shutdown timer */ ctx->shutdown_warning_time.val = 0; /* If AC is not present, switch to discharging state */ if (!ctx->curr.ac) return PWR_STATE_DISCHARGE; /* Check general error conditions */ if (ctx->curr.error) return PWR_STATE_ERROR; /* Send battery event to host */ host_set_single_event(EC_HOST_EVENT_BATTERY); return PWR_STATE_IDLE0; }
static void bd99995_init(void) { int reg; const struct battery_info *bi = battery_get_info(); /* Disable BC1.2 detection on VCC */ if (ch_raw_read16(BD99955_CMD_VCC_UCD_SET, ®, BD99955_EXTENDED_COMMAND)) return; reg &= ~BD99955_CMD_UCD_SET_USBDETEN; ch_raw_write16(BD99955_CMD_VCC_UCD_SET, reg, BD99955_EXTENDED_COMMAND); /* Disable BC1.2 detection on VBUS */ if (ch_raw_read16(BD99955_CMD_VBUS_UCD_SET, ®, BD99955_EXTENDED_COMMAND)) return; reg &= ~BD99955_CMD_UCD_SET_USBDETEN; ch_raw_write16(BD99955_CMD_VBUS_UCD_SET, reg, BD99955_EXTENDED_COMMAND); /* Disable BC1.2 charge enable trigger */ if (ch_raw_read16(BD99955_CMD_CHGOP_SET1, ®, BD99955_EXTENDED_COMMAND)) return; reg |= (BD99955_CMD_CHGOP_SET1_VCC_BC_DISEN | BD99955_CMD_CHGOP_SET1_VBUS_BC_DISEN); ch_raw_write16(BD99955_CMD_CHGOP_SET1, reg, BD99955_EXTENDED_COMMAND); /* Set battery OVP to 500 + maximum battery voltage */ ch_raw_write16(BD99955_CMD_VBATOVP_SET, (bi->voltage_max + 500) & 0x7ff0, BD99955_EXTENDED_COMMAND); }
static int battery_discharging_range(int deci_k) { int8_t temp_c = DECI_KELVIN_TO_CELSIUS(deci_k); const struct battery_info *info = battery_get_info(); return (temp_c >= info->discharging_min_c && temp_c < info->discharging_max_c); }
int charger_profile_override(struct charge_state_data *curr) { const struct battery_info *batt_info; /* battery temp in 0.1 deg C */ int bat_temp_c = curr->batt.temperature - 2731; batt_info = battery_get_info(); /* Don't charge if outside of allowable temperature range */ if (bat_temp_c >= batt_info->charging_max_c * 10 || bat_temp_c < batt_info->charging_min_c * 10) { curr->requested_current = 0; curr->requested_voltage = 0; curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE; curr->state = ST_IDLE; } return 0; }
static void charge_init(void) { struct charge_state_context *ctx = &task_ctx; ctx->prev.state = PWR_STATE_INIT; ctx->curr.state = PWR_STATE_INIT; ctx->trickle_charging_time.val = 0; ctx->battery = battery_get_info(); ctx->charger = charger_get_info(); /* Assume the battery is responsive until proven otherwise */ ctx->battery_responsive = 1; /* Set up LPC direct memmap */ ctx->memmap_batt_volt = (uint32_t *)host_get_memmap(EC_MEMMAP_BATT_VOLT); ctx->memmap_batt_rate = (uint32_t *)host_get_memmap(EC_MEMMAP_BATT_RATE); ctx->memmap_batt_cap = (uint32_t *)host_get_memmap(EC_MEMMAP_BATT_CAP); ctx->memmap_batt_flags = host_get_memmap(EC_MEMMAP_BATT_FLAG); }
static ssize_t factory_show_property(struct device *dev, struct device_attribute *attr, char *buf) { struct battery_info *info = dev_get_drvdata(dev->parent); int i; int cnt, dat, d_max, d_min, d_total; int val; const ptrdiff_t off = attr - factory_attrs; pr_debug("%s: %s\n", __func__, factory_attrs[off].attr.name); i = 0; val = 0; switch (off) { case BATT_READ_RAW_SOC: battery_update_info(info); val = info->battery_raw_soc; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_READ_ADJ_SOC: battery_get_info(info, POWER_SUPPLY_PROP_CAPACITY); val = info->battery_soc; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_TYPE: i += scnprintf(buf + i, PAGE_SIZE - i, "SDI_SDI\n"); break; case BATT_TEMP_ADC: battery_get_info(info, POWER_SUPPLY_PROP_TEMP); val = info->battery_temper_adc; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_TEMP_AVER: val = 0; for (cnt = 0; cnt < CNT_TEMPER_AVG; cnt++) { msleep(100); battery_get_info(info, POWER_SUPPLY_PROP_TEMP); val += info->battery_temper_adc; info->battery_temper_adc_avg = val / (cnt + 1); } #ifdef CONFIG_S3C_ADC info->battery_temper_avg = info->pdata->covert_adc( info->battery_temper_adc_avg, info->pdata->temper_ch); #else info->battery_temper_avg = info->battery_temper; #endif val = info->battery_temper_avg; pr_info("%s: temper avg(%d)\n", __func__, val); i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_TEMP_ADC_AVER: val = info->battery_temper_adc_avg; pr_info("%s: temper adc avg(%d)\n", __func__, val); i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_VOL_AVER: /* not use POWER_SUPPLY_PROP_VOLTAGE_AVG */ val = dat = d_max = d_min = d_total = 0; for (cnt = 0; cnt < CNT_VOLTAGE_AVG; cnt++) { msleep(200); dat = battery_get_info(info, POWER_SUPPLY_PROP_VOLTAGE_NOW); if (cnt != 0) { d_max = max(dat, d_max); d_min = min(dat, d_min); } else d_max = d_min = dat; d_total += dat; } val = (d_total - d_max - d_min) / (CNT_VOLTAGE_AVG - 2); pr_info("%s: voltage avg(%d)\n", __func__, val); i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_VFOCV: battery_update_info(info); val = info->battery_vfocv; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_LP_CHARGING: val = info->lpm_state; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_CHARGING_SOURCE: battery_get_info(info, POWER_SUPPLY_PROP_ONLINE); val = info->cable_type; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case TEST_MODE: val = info->battery_test_mode; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_ERROR_TEST: i += scnprintf(buf + i, PAGE_SIZE - i, "(%d): 0: normal, 1: full charged, 2: freezed, 3: overheated, 4: ovp, 5: vf\n", info->battery_error_test); break; case SIOP_ACTIVATED: val = info->siop_state; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case WC_STATUS: case WPC_PIN_STATE: #ifdef CONFIG_BATTERY_WPC_CHARGER val = !gpio_get_value(GPIO_WPC_INT); #else val = false; #endif i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case FACTORY_MODE: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", info->factory_mode); break; case BATT_VOL_ADC: case BATT_VOL_ADC_CAL: case BATT_VOL_ADC_AVER: case BATT_TEMP_ADC_CAL: case BATT_VF_ADC: case AUTH_BATTERY: i += scnprintf(buf + i, PAGE_SIZE - i, "N/A\n"); break; #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) case BATT_SYSREV: val = system_rev; i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val); break; case BATT_TEMP_ADC_SPEC: i += scnprintf(buf + i, PAGE_SIZE - i, "(HIGH: %d / %d, LOW: %d / %d)\n", info->pdata->overheat_stop_temp, info->pdata->overheat_recovery_temp, info->pdata->freeze_stop_temp, info->pdata->freeze_recovery_temp); break; #endif default: i = -EINVAL; } return i; }
/* Main loop */ void charger_task(void) { int sleep_usec; int need_static = 1; const struct charger_info * const info = charger_get_info(); /* Get the battery-specific values */ batt_info = battery_get_info(); prev_ac = prev_charge = -1; chg_ctl_mode = CHARGE_CONTROL_NORMAL; shutdown_warning_time.val = 0UL; battery_seems_to_be_dead = 0; /* * If system is not locked and we don't have a battery to live on, * then use max input current limit so that we can pull as much power * as needed. */ battery_get_params(&curr.batt); prev_bp = curr.batt.is_present; curr.desired_input_current = get_desired_input_current(prev_bp, info); while (1) { #ifdef CONFIG_SB_FIRMWARE_UPDATE if (sb_fw_update_in_progress()) { task_wait_event(CHARGE_MAX_SLEEP_USEC); continue; } #endif /* Let's see what's going on... */ curr.ts = get_time(); sleep_usec = 0; problems_exist = 0; curr.ac = extpower_is_present(); if (curr.ac != prev_ac) { if (curr.ac) { /* * Some chargers are unpowered when the AC is * off, so we'll reinitialize it when AC * comes back and set the input current limit. * Try again if it fails. */ int rv = charger_post_init(); if (rv != EC_SUCCESS) { problem(PR_POST_INIT, rv); } else { if (curr.desired_input_current != CHARGE_CURRENT_UNINITIALIZED) rv = charger_set_input_current( curr.desired_input_current); if (rv != EC_SUCCESS) problem(PR_SET_INPUT_CURR, rv); else prev_ac = curr.ac; } } else { /* Some things are only meaningful on AC */ chg_ctl_mode = CHARGE_CONTROL_NORMAL; battery_seems_to_be_dead = 0; prev_ac = curr.ac; } } charger_get_params(&curr.chg); battery_get_params(&curr.batt); if (prev_bp != curr.batt.is_present) { prev_bp = curr.batt.is_present; /* Update battery info due to change of battery */ batt_info = battery_get_info(); need_static = 1; curr.desired_input_current = get_desired_input_current(prev_bp, info); if (curr.desired_input_current != CHARGE_CURRENT_UNINITIALIZED) charger_set_input_current( curr.desired_input_current); hook_notify(HOOK_BATTERY_SOC_CHANGE); } /* * TODO(crosbug.com/p/27527). Sometimes the battery thinks its * temperature is 6280C, which seems a bit high. Let's ignore * anything above the boiling point of tungsten until this bug * is fixed. If the battery is really that warm, we probably * have more urgent problems. */ if (curr.batt.temperature > CELSIUS_TO_DECI_KELVIN(5660)) { CPRINTS("ignoring ridiculous batt.temp of %dC", DECI_KELVIN_TO_CELSIUS(curr.batt.temperature)); curr.batt.flags |= BATT_FLAG_BAD_TEMPERATURE; } /* If the battery thinks it's above 100%, don't believe it */ if (curr.batt.state_of_charge > 100) { CPRINTS("ignoring ridiculous batt.soc of %d%%", curr.batt.state_of_charge); curr.batt.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; } /* * Now decide what we want to do about it. We'll normally just * pass along whatever the battery wants to the charger. Note * that if battery_get_params() can't get valid values from the * battery it uses (0, 0), which is probably safer than blindly * applying power to a battery we can't talk to. */ curr.requested_voltage = curr.batt.desired_voltage; curr.requested_current = curr.batt.desired_current; /* If we *know* there's no battery, wait for one to appear. */ if (curr.batt.is_present == BP_NO) { ASSERT(curr.ac); /* How are we running? */ curr.state = ST_IDLE; curr.batt_is_charging = 0; battery_was_removed = 1; goto wait_for_it; } /* * If we had trouble talking to the battery or the charger, we * should probably do nothing for a bit, and if it doesn't get * better then flag it as an error. */ if (curr.chg.flags & CHG_FLAG_BAD_ANY) problem(PR_CHG_FLAGS, curr.chg.flags); if (curr.batt.flags & BATT_FLAG_BAD_ANY) problem(PR_BATT_FLAGS, curr.batt.flags); /* * If AC is present, check if input current is sufficient to * actually charge battery. */ curr.batt_is_charging = curr.ac && (curr.batt.current >= 0); /* Don't let the battery hurt itself. */ shutdown_on_critical_battery(); if (!curr.ac) { curr.state = ST_DISCHARGE; goto wait_for_it; } /* Okay, we're on AC and we should have a battery. */ /* Used for factory tests. */ if (chg_ctl_mode != CHARGE_CONTROL_NORMAL) { curr.state = ST_IDLE; goto wait_for_it; } /* If the battery is not responsive, try to wake it up. */ if (!(curr.batt.flags & BATT_FLAG_RESPONSIVE)) { if (battery_seems_to_be_dead || battery_is_cut_off()) { /* It's dead, do nothing */ curr.state = ST_IDLE; curr.requested_voltage = 0; curr.requested_current = 0; } else if (curr.state == ST_PRECHARGE && (get_time().val > precharge_start_time.val + PRECHARGE_TIMEOUT_US)) { /* We've tried long enough, give up */ CPRINTS("battery seems to be dead"); battery_seems_to_be_dead = 1; curr.state = ST_IDLE; curr.requested_voltage = 0; curr.requested_current = 0; } else { /* See if we can wake it up */ if (curr.state != ST_PRECHARGE) { CPRINTS("try to wake battery"); precharge_start_time = get_time(); need_static = 1; } curr.state = ST_PRECHARGE; curr.requested_voltage = batt_info->voltage_max; curr.requested_current = batt_info->precharge_current; } goto wait_for_it; } else { /* The battery is responding. Yay. Try to use it. */ #ifdef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD /* * TODO (crosbug.com/p/29467): remove this workaround * for dead battery that requests no voltage/current */ if (curr.requested_voltage == 0 && curr.requested_current == 0 && curr.batt.state_of_charge == 0) { /* Battery is dead, give precharge current */ curr.requested_voltage = batt_info->voltage_max; curr.requested_current = batt_info->precharge_current; } else #endif #ifdef CONFIG_BATTERY_REVIVE_DISCONNECT battery_seems_to_be_disconnected = 0; if (curr.requested_voltage == 0 && curr.requested_current == 0 && battery_get_disconnect_state() == BATTERY_DISCONNECTED) { /* * Battery is in disconnect state. Apply a * current to kick it out of this state. */ CPRINTS("found battery in disconnect state"); curr.requested_voltage = batt_info->voltage_max; curr.requested_current = batt_info->precharge_current; battery_seems_to_be_disconnected = 1; } else #endif if (curr.state == ST_PRECHARGE || battery_seems_to_be_dead || battery_was_removed) { CPRINTS("battery woke up"); /* Update the battery-specific values */ batt_info = battery_get_info(); need_static = 1; } battery_seems_to_be_dead = battery_was_removed = 0; curr.state = ST_CHARGE; } /* * TODO(crosbug.com/p/27643): Quit trying if charging too long * without getting full (CONFIG_CHARGER_TIMEOUT_HOURS). */ wait_for_it: #ifdef CONFIG_CHARGER_PROFILE_OVERRIDE sleep_usec = charger_profile_override(&curr); if (sleep_usec < 0) problem(PR_CUSTOM, sleep_usec); #endif /* Keep the AP informed */ if (need_static) need_static = update_static_battery_info(); /* Wait on the dynamic info until the static info is good. */ if (!need_static) update_dynamic_battery_info(); notify_host_of_low_battery(); /* And the EC console */ is_full = calc_is_full(); if ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && curr.batt.state_of_charge != prev_charge) || (is_full != prev_full)) { show_charging_progress(); prev_charge = curr.batt.state_of_charge; hook_notify(HOOK_BATTERY_SOC_CHANGE); } prev_full = is_full; /* Turn charger off if it's not needed */ if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) { curr.requested_voltage = 0; curr.requested_current = 0; } /* Apply external limits */ if (curr.requested_current > user_current_limit) curr.requested_current = user_current_limit; /* Round to valid values */ curr.requested_voltage = charger_closest_voltage(curr.requested_voltage); curr.requested_current = charger_closest_current(curr.requested_current); /* Charger only accpets request when AC is on. */ if (curr.ac) { /* * Some batteries would wake up after cut-off if we keep * charging it. Thus, we only charge when AC is on and * battery is not cut off yet. */ if (battery_is_cut_off()) charge_request(0, 0); /* * As a safety feature, some chargers will stop * charging if we don't communicate with it frequently * enough. In manual mode, we'll just tell it what it * knows. */ else if (manual_mode) { charge_request(curr.chg.voltage, curr.chg.current); } else { charge_request(curr.requested_voltage, curr.requested_current); } } else { charge_request( charger_closest_voltage( curr.batt.voltage + info->voltage_step), -1); } /* How long to sleep? */ if (problems_exist) /* If there are errors, don't wait very long. */ sleep_usec = CHARGE_POLL_PERIOD_SHORT; else if (sleep_usec <= 0) { /* default values depend on the state */ if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) { /* If AP is off, we can sleep a long time */ if (chipset_in_state(CHIPSET_STATE_ANY_OFF | CHIPSET_STATE_SUSPEND)) sleep_usec = CHARGE_POLL_PERIOD_VERY_LONG; else /* Discharging, not too urgent */ sleep_usec = CHARGE_POLL_PERIOD_LONG; } else { /* Charging, so pay closer attention */ sleep_usec = CHARGE_POLL_PERIOD_CHARGE; } } /* Adjust for time spent in this loop */ sleep_usec -= (int)(get_time().val - curr.ts.val); if (sleep_usec < CHARGE_MIN_SLEEP_USEC) sleep_usec = CHARGE_MIN_SLEEP_USEC; else if (sleep_usec > CHARGE_MAX_SLEEP_USEC) sleep_usec = CHARGE_MAX_SLEEP_USEC; task_wait_event(sleep_usec); } }
/* * Ask the charger for some voltage and current. If either value is 0, * charging is disabled; otherwise it's enabled. Negative values are ignored. */ static int charge_request(int voltage, int current) { int r1 = EC_SUCCESS, r2 = EC_SUCCESS, r3 = EC_SUCCESS; static int __bss_slow prev_volt, prev_curr; if (!voltage || !current) { #ifdef CONFIG_CHARGER_NARROW_VDC current = 0; /* With NVDC charger, keep VSYS voltage higher than battery */ voltage = charger_closest_voltage( curr.batt.voltage + charger_get_info()->voltage_step); /* If the battery is full, request the max voltage. */ if (is_full) voltage = battery_get_info()->voltage_max; /* And handle dead battery case */ voltage = MAX(voltage, battery_get_info()->voltage_min); #else voltage = current = 0; #endif } if (curr.ac) { if (prev_volt != voltage || prev_curr != current) CPRINTS("%s(%dmV, %dmA)", __func__, voltage, current); } /* * Set current before voltage so that if we are just starting * to charge, we allow some time (i2c delay) for charging circuit to * start at a voltage just above battery voltage before jumping * up. This helps avoid large current spikes when connecting * battery. */ if (current >= 0) r2 = charger_set_current(current); if (r2 != EC_SUCCESS) problem(PR_SET_CURRENT, r2); if (voltage >= 0) r1 = charger_set_voltage(voltage); if (r1 != EC_SUCCESS) problem(PR_SET_VOLTAGE, r1); /* * Set the charge inhibit bit when possible as it appears to save * power in some cases (e.g. Nyan with BQ24735). */ #if defined(CONFIG_CHARGER_BD99955) || defined(CONFIG_CHARGER_BD99956) /* Charger auto exits from battery learn mode if charge inhibited */ if (current > 0 || chg_ctl_mode == CHARGE_CONTROL_DISCHARGE) #else if (voltage > 0 || current > 0) #endif r3 = charger_set_mode(0); else r3 = charger_set_mode(CHARGE_FLAG_INHIBIT_CHARGE); if (r3 != EC_SUCCESS) problem(PR_SET_MODE, r3); /* * Only update if the request worked, so we'll keep trying on failures. */ if (!r1 && !r2) { prev_volt = voltage; prev_curr = current; } return r1 ? r1 : r2; }
static void battery_charge_control(struct battery_info *info, int enable, int set_current) { ktime_t ktime; struct timespec current_time; pr_debug("%s\n", __func__); ktime = alarm_get_elapsed_realtime(); current_time = ktime_to_timespec(ktime); if (set_current == CHARGER_KEEP_CURRENT) goto charge_state_control; if (info->siop_state == true) { pr_debug("%s: siop state, charge current is %dmA\n", __func__, info->siop_charge_current); set_current = info->siop_charge_current; } /* check charge current before and after */ if (info->charge_current == ((set_current * 3 / 100) * 333 / 10)) { /* * (current * 3 / 100) is converted value * for register setting. * (register current * 333 / 10) is actual value * for charging */ pr_debug("%s: same charge current: %dmA\n", __func__, set_current); } else { battery_control_info(info, POWER_SUPPLY_PROP_CURRENT_NOW, set_current); pr_info("%s: update charge current: %dmA\n", __func__, set_current); } info->charge_current = battery_get_info(info, POWER_SUPPLY_PROP_CURRENT_NOW); charge_state_control: /* check charge state before and after */ if ((enable == CHARGE_ENABLE) && (info->charge_start_time == 0)) { battery_control_info(info, POWER_SUPPLY_PROP_STATUS, CHARGE_ENABLE); info->charge_start_time = current_time.tv_sec; pr_info("%s: charge enabled, current as %dmA @%d\n", __func__, info->charge_current, info->charge_start_time); } else if ((enable == CHARGE_DISABLE) && (info->charge_start_time != 0)) { battery_control_info(info, POWER_SUPPLY_PROP_STATUS, CHARGE_DISABLE); pr_info("%s: charge disabled, current as %dmA @%d\n", __func__, info->charge_current, (int)current_time.tv_sec); info->charge_start_time = 0; } else { pr_debug("%s: same charge state(%s), current as %dmA @%d\n", __func__, (enable ? "enabled" : "disabled"), info->charge_current, info->charge_start_time); } info->charge_real_state = info->charge_virt_state = battery_get_info(info, POWER_SUPPLY_PROP_STATUS); }
static ssize_t factory_store_property(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct battery_info *info = dev_get_drvdata(dev->parent); int x; int ret; const ptrdiff_t off = attr - factory_attrs; pr_info("%s: %s\n", __func__, factory_attrs[off].attr.name); x = 0; ret = 0; switch (off) { case BATT_RESET_SOC: if (sscanf(buf, "%d\n", &x) == 1) { if (x == 1) { pr_info("%s: Reset SOC.\n", __func__); battery_control_info(info, POWER_SUPPLY_PROP_CAPACITY, 1); info->battery_soc = battery_get_info(info, POWER_SUPPLY_PROP_CAPACITY); } else pr_info("%s: Not supported param.\n", __func__); ret = count; } break; case TEST_MODE: if (sscanf(buf, "%d\n", &x) == 1) { info->battery_test_mode = x; pr_info("%s: battery test mode: %d\n", __func__, info->battery_test_mode); ret = count; } break; case BATT_ERROR_TEST: if (sscanf(buf, "%d\n", &x) == 1) { info->battery_error_test = x; pr_info("%s: battery error test: %d\n", __func__, info->battery_error_test); ret = count; } break; case SIOP_ACTIVATED: if (sscanf(buf, "%d\n", &x) == 1) { info->siop_state = x; if (info->siop_state == SIOP_ACTIVE) info->siop_charge_current = info->pdata->chg_curr_usb; pr_info("%s: SIOP %s\n", __func__, (info->siop_state ? "activated" : "deactivated")); ret = count; } break; case FACTORY_MODE: if (sscanf(buf, "%d\n", &x) == 1) { if (x) info->factory_mode = true; else info->factory_mode = false; pr_info("%s: factory mode %s\n", __func__, (info->factory_mode ? "set" : "clear")); ret = count; } break; case UPDATE: pr_info("%s: battery update\n", __func__); ret = count; break; case BATT_SLATE_MODE: if (sscanf(buf, "%d\n", &x) == 1) { if (x) info->slate_mode = 1; else info->slate_mode = 0; pr_info("%s: slate_mode %s\n", __func__, (info->slate_mode ? "set" : "clear")); ret = count; } break; default: ret = -EINVAL; } schedule_work(&info->monitor_work); return ret; }
int16_t battery_get_parameter_value(uint8_t parameter) { uint16_t value; os_enterCS(); switch(parameter) { case MODEL_TYPE: value = 1; break; case PROGRAM_REV: value = 530; break; case PAR_TAB_REV: value = 530; break; case NENNSPNG: value = 35520; break; case NENNSTROM: value = 2500; break; case SERIE_NUMMER: value = 11178; break; case REP_DATUM: value = 0; break; case STANDZEIT: value = 64; break; case FAHR_LADE_ZEIT: value = 9; break; case LAST_ERROR: value = 0; break; case BUS_ADRESSE: value = battery.address; break; case DRIVE_STATE: value = plc_get_drive_state(); break; case COMMAND: value = !battery_info_get(BAT_REL_OPEN); break; case PARAM_PROT: value = 0; break; case BINFO: value = battery_get_info(); break; // We simulate 3 batteries. Thus each of them reports one third of the real value. case IST_STROM: value = 0; break; case LADESTROM: value = 400; break; case FAHRSTROM: value = -800; break; case TOTAL_SPANNUNG: value = 0; break; case SOLL_LADESPG: value = 40000; break; // We simulate 3 batteries. Thus each of them reports one third of the real value. case AH_ZAEHLER: value = battery.ah_counter; break; case Q: value = -1400; break; case LEISTUNG: value = 0; break; case BATTERIE_TEMP: value = 0; break; case FINFO: value = 0; break; case SYM_SPANNUNG: value = 26; break; case TEILSPANNUNG1: value = 5100; break; case TEILSPANNUNG2: value = 5100; break; case TEILSPANNUNG3: value = 5100; break; case TEILSPANNUNG4: value = 5100; break; case TEILSPANNUNG5: value = 5100; break; case TEILSPANNUNG6: value = 5100; break; case TEILSPANNUNG7: value = 5100; break; case TEMPERATUR1: value = battery.temperatur_1; break; case TEMPERATUR2: value = battery.temperatur_2; break; case TEMPERATUR3: value = battery.temperatur_3; break; case TEMPERATUR4: value = battery.temperatur_4; break; case TEMPERATUR5: value = battery.temperatur_5; break; case TEMPERATUR6: value = battery.temperatur_6; break; case TEMPERATUR7: value = battery.temperatur_7; break; case TEMPERATUR8: value = battery.temperatur_8; break; case TEMPERATUR9: value = battery.temperatur_9; break; case TEMPERATUR10: value = battery.temperatur_10; break; case TEMPERATUR11: value = battery.temperatur_11; break; case TEMPERATUR12: value = battery.temperatur_12; break; case TEMPERATUR13: value = battery.temperatur_13; break; case TEMPERATUR14: value = battery.temperatur_14; break; case PC_CALIBR_TEMP: value = 0x5678; break; case MAX_BAT_TEMP: value = 0; break; case UMGEBUNGS_TEMP: value = 0; break; case MAX_LADETEMP: value = 4500; break; case MIN_LADETEMP: value = 0; break; case MAX_FAHRTEMP: value = 4500; break; case MIN_FAHRTEMP: value = 0; break; case MAX_LAGERTEMP: value = 4500; break; case MIN_LAGERTEMP: value = 0; break; case MAX_KAPAZITAET: value = 305; break; case MIN_KAPAZITAET: value = 280; break; case GELADENE_AH: value = 0; break; case ENTLADENE_AH: value = 0; break; case LADEZYKLEN: value = 0; break; case TIEFENTLADE_ZYKLEN: value = 0; break; case MAX_ENTLADE_STROM: value = -800; break; // Times 3 blocks -> 24A case ZYKLUS_UEBER_110: value = 0; break; case ZYKLUS_UEBER_100: value = 0; break; case ZYKLUS_UEBER_90: value = 0; break; case ZYKLUS_UEBER_80: value = 0; break; case ZYKLUS_UEBER_70: value = 0; break; case ZYKLUS_UEBER_60: value = 0; break; case ZYKLUS_UEBER_50: value = 0; break; case ZYKLUS_UEBER_40: value = 0; break; case ZYKLUS_UEBER_30: value = 0; break; case ZYKLUS_UEBER_20: value = 0; break; case ZYKLUS_UEBER_10: value = 0; break; case ZYKLUS_UNTER_10: value = 0; break; case MAX_UEBERLADUNG: value = 850; break; case MIN_LDG_F_VOLL: value = -500; break; case STROM_ZUNAHME: value = 40; break; case MAX_LADE_SPG: value = 40000; break; case MIN_LADE_TEMP: value = 0; break; case MAX_LADE_TEMP: value = 4500; break; case MAX_TEMP_ZUNAHME: value = 100; break; case MAX_LADEZEIT: value = 800; break; case SYMMETRIER_STROM: value = 28; break; case LADE_STR_UNTER_M10: value = 56; break; case LADE_STR_UEBER_M10: value = 56; break; case LADE_STR_UEBER_P00: value = 280; break; case LADE_STR_UEBER_P10: value = 280; break; case LADE_STR_UEBER_P20: value = 280; break; case LADE_STR_UEBER_P30: value = 280; break; case LADE_STR_UEBER_P40: value = 79; break; case LADE_STR_UEBER_P45: value = 28; break; case LADE_STR_UEBER_P50: value = 28; break; case LADE_SPG_UNTER_M10: value = 40000; break; case LADE_SPG_UEBER_M10: value = 40000; break; case LADE_SPG_UEBER_P00: value = 40000; break; case LADE_SPG_UEBER_P10: value = 40000; break; case LADE_SPG_UEBER_P20: value = 40000; break; case LADE_SPG_UEBER_P30: value = 40000; break; case LADE_SPG_UEBER_P40: value = 37440; break; case LADE_SPG_UEBER_P45: value = 36480; break; case LADE_SPG_UEBER_P50: value = 35520; break; case NOM_KAPAZITAET: value = 3; break; case MIN_FAHR_SPANNUNG: value = 31000; break; case SELBST_ENTL_STROM: value = 28000; break; case TIEFENTLADE_SPG: value = TIEFENTLADE_SPANNUNG; break; case MAX_SPANNUNG_DIFF: value = 500; break; case MIN_FAHR_TEMP_B: value = -2500; break; case MAX_FAHR_TEMP_B: value = 6000; break; case MAX_FAHR_STROM: value = -1000; break; case AD_STROM: value = 0x817F; break; case KAL_TEMP_7_6: value = 0xFFFF; break; case KAL_TEMP_5_4: value = 0xFEFD; break; case KAL_TEMP_3_2: value = 0xFCFD; break; case KAL_TEMP_1_AMB: value = 0x00FE; break; case KAL_TEMP_GD_14: value = 0x7C00; break; case KAL_TEMP_13_12: value = 0x00FF; break; case KAL_TEMP_11_10: value = 0xFE00; break; case KAL_TEMP_9_8: value = 0x0002; break; case SENSOR_MASK: value = 0x0000; break; case OFFS_KLEIN_STL: value = 1508; break; case OFFS_GROSS_STL: value = 12523; break; case KALIB_SPG_1: value = 0x00A3; break; case KALIB_SPG_2: value = 0x009F; break; case KALIB_SPG_3: value = 0x00A6; break; case KALIB_SPG_4: value = 0x00B1; break; case KALIB_SPG_5: value = 0x007C; break; case KALIB_SPG_6: value = 0x00A7; break; case KALIB_SPG_9: value = 0x00A7; break; case DEBUG_VALUE_C: value = 22498; break; case DEBUG_VALUE_H: value = 0x57E2; break; case DEBUG_VALUE_ADDR: value = 0xFFFF; break; case GESCHWINDIGKEIT: value = 0; break; case TAGESKILOMETER: value = 0; break; default: value = 0x0000; error(ERROR_UNKNOWN_PARAMETER); } os_exitCS(); return value; }