| /* Copyright 2012 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * Common battery command. |
| */ |
| |
| #include "battery.h" |
| #include "charge_state.h" |
| #include "common.h" |
| #include "console.h" |
| #include "ec_ec_comm_client.h" |
| #include "extpower.h" |
| #include "gpio.h" |
| #include "hooks.h" |
| #include "host_command.h" |
| #include "timer.h" |
| #include "util.h" |
| #include "watchdog.h" |
| |
| #define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) |
| #define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) |
| #define CUTOFFPRINTS(info) CPRINTS("%s %s", "Battery cut off", info) |
| |
| /* See config.h for details */ |
| const static int batt_full_factor = CONFIG_BATT_FULL_FACTOR; |
| const static int batt_host_full_factor = CONFIG_BATT_HOST_FULL_FACTOR; |
| const static int batt_host_shutdown_pct = CONFIG_BATT_HOST_SHUTDOWN_PERCENTAGE; |
| |
| #ifdef CONFIG_BATTERY_V2 |
| /* |
| * Store battery information in these 2 structures. Main (lid) battery is always |
| * at index 0, and secondary (base) battery at index 1. |
| */ |
| struct ec_response_battery_static_info_v1 battery_static[CONFIG_BATTERY_COUNT]; |
| struct ec_response_battery_dynamic_info battery_dynamic[CONFIG_BATTERY_COUNT]; |
| #endif |
| |
| #ifdef CONFIG_BATTERY_CUT_OFF |
| |
| #ifndef CONFIG_BATTERY_CUTOFF_DELAY_US |
| #define CONFIG_BATTERY_CUTOFF_DELAY_US (1 * SECOND) |
| #endif |
| |
| static enum battery_cutoff_states battery_cutoff_state = |
| BATTERY_CUTOFF_STATE_NORMAL; |
| |
| #endif |
| |
| #ifdef CONFIG_BATTERY_PRESENT_GPIO |
| #ifdef CONFIG_BATTERY_PRESENT_CUSTOM |
| #error "Don't define both CONFIG_BATTERY_PRESENT_CUSTOM and" \ |
| "CONFIG_BATTERY_PRESENT_GPIO" |
| #endif |
| /** |
| * Physical detection of battery. |
| */ |
| enum battery_present battery_is_present(void) |
| { |
| /* The GPIO is low when the battery is present */ |
| return gpio_get_level(CONFIG_BATTERY_PRESENT_GPIO) ? BP_NO : BP_YES; |
| } |
| #endif |
| |
| static const char *get_error_text(int rv) |
| { |
| if (rv == EC_ERROR_UNIMPLEMENTED) |
| return "(unsupported)"; |
| else |
| return "(error)"; |
| } |
| |
| static void print_item_name(const char *name) |
| { |
| ccprintf(" %-11s", name); |
| } |
| |
| static int check_print_error(int rv) |
| { |
| if (rv != EC_SUCCESS) |
| ccprintf("%s\n", get_error_text(rv)); |
| return rv == EC_SUCCESS; |
| } |
| |
| static void print_battery_status(void) |
| { |
| static const char * const st[] = {"EMPTY", "FULL", "DCHG", "INIT",}; |
| static const char * const al[] = {"RT", "RC", "--", "TD", |
| "OT", "--", "TC", "OC"}; |
| |
| int value, i; |
| |
| print_item_name("Status:"); |
| if (check_print_error(battery_status(&value))) { |
| ccprintf("0x%04x", value); |
| |
| /* bits 0-3 are only valid when the previous transaction |
| * failed, so ignore them */ |
| |
| /* bits 4-7 are status */ |
| for (i = 0; i < 4; i++) |
| if (value & (1 << (i+4))) |
| ccprintf(" %s", st[i]); |
| |
| /* bits 15-8 are alarms */ |
| for (i = 0; i < 8; i++) |
| if (value & (1 << (i+8))) |
| ccprintf(" %s", al[i]); |
| |
| ccprintf("\n"); |
| } |
| } |
| |
| static void print_battery_strings(void) |
| { |
| char text[32]; |
| |
| print_item_name("Manuf:"); |
| if (check_print_error(battery_manufacturer_name(text, sizeof(text)))) |
| ccprintf("%s\n", text); |
| |
| print_item_name("Device:"); |
| if (check_print_error(battery_device_name(text, sizeof(text)))) |
| ccprintf("%s\n", text); |
| |
| print_item_name("Chem:"); |
| if (check_print_error(battery_device_chemistry(text, sizeof(text)))) |
| ccprintf("%s\n", text); |
| } |
| |
| static void print_battery_params(void) |
| { |
| #if defined(HAS_TASK_CHARGER) |
| /* Ask charger so that we don't need to ask battery again. */ |
| const struct batt_params *batt = charger_current_battery_params(); |
| #else |
| /* This is for test code, where doesn't have charger task. */ |
| struct batt_params _batt; |
| const struct batt_params *batt = &_batt; |
| |
| battery_get_params(&_batt); |
| #endif |
| |
| print_item_name("Param flags:"); |
| ccprintf("%08x\n", batt->flags); |
| |
| print_item_name("Temp:"); |
| ccprintf("0x%04x = %.1d K (%.1d C)\n", |
| batt->temperature, |
| batt->temperature, |
| batt->temperature - 2731); |
| |
| print_item_name("V:"); |
| ccprintf("0x%04x = %d mV\n", batt->voltage, batt->voltage); |
| |
| print_item_name("V-desired:"); |
| ccprintf("0x%04x = %d mV\n", batt->desired_voltage, |
| batt->desired_voltage); |
| |
| print_item_name("I:"); |
| ccprintf("0x%04x = %d mA", batt->current & 0xffff, batt->current); |
| if (batt->current > 0) |
| ccputs("(CHG)"); |
| else if (batt->current < 0) |
| ccputs("(DISCHG)"); |
| ccputs("\n"); |
| |
| print_item_name("I-desired:"); |
| ccprintf("0x%04x = %d mA\n", batt->desired_current, |
| batt->desired_current); |
| |
| print_item_name("Charging:"); |
| ccprintf("%sAllowed\n", |
| batt->flags & BATT_FLAG_WANT_CHARGE ? "" : "Not "); |
| |
| print_item_name("Charge:"); |
| ccprintf("%d %%\n", batt->state_of_charge); |
| } |
| |
| static void print_battery_info(void) |
| { |
| int value; |
| int hour, minute; |
| |
| print_item_name("Serial:"); |
| if (check_print_error(battery_serial_number(&value))) |
| ccprintf("0x%04x\n", value); |
| |
| print_item_name("V-design:"); |
| if (check_print_error(battery_design_voltage(&value))) |
| ccprintf("0x%04x = %d mV\n", value, value); |
| |
| print_item_name("Mode:"); |
| if (check_print_error(battery_get_mode(&value))) |
| ccprintf("0x%04x\n", value); |
| |
| print_item_name("Abs charge:"); |
| if (check_print_error(battery_state_of_charge_abs(&value))) |
| ccprintf("%d %%\n", value); |
| |
| print_item_name("Remaining:"); |
| if (check_print_error(battery_remaining_capacity(&value))) |
| ccprintf("%d mAh\n", value); |
| |
| print_item_name("Cap-full:"); |
| if (check_print_error(battery_full_charge_capacity(&value))) |
| ccprintf("%d mAh (%d mAh with %d %% compensation)\n", |
| value, value*batt_full_factor/100, batt_full_factor); |
| |
| #ifdef CONFIG_CHARGER |
| print_item_name("Display:"); |
| value = charge_get_display_charge(); |
| ccprintf("%d.%d %%\n", value / 10, value % 10); |
| #endif |
| |
| print_item_name(" Design:"); |
| if (check_print_error(battery_design_capacity(&value))) |
| ccprintf("%d mAh\n", value); |
| |
| print_item_name("Time-full:"); |
| if (check_print_error(battery_time_to_full(&value))) { |
| if (value == 65535) { |
| hour = 0; |
| minute = 0; |
| } else { |
| hour = value / 60; |
| minute = value % 60; |
| } |
| ccprintf("%dh:%d\n", hour, minute); |
| } |
| |
| print_item_name(" Empty:"); |
| if (check_print_error(battery_time_to_empty(&value))) { |
| if (value == 65535) { |
| hour = 0; |
| minute = 0; |
| } else { |
| hour = value / 60; |
| minute = value % 60; |
| } |
| ccprintf("%dh:%d\n", hour, minute); |
| } |
| } |
| |
| void print_battery_debug(void) |
| { |
| print_battery_status(); |
| print_battery_params(); |
| print_battery_strings(); |
| print_battery_info(); |
| } |
| |
| static int command_battery(int argc, char **argv) |
| { |
| int repeat = 1; |
| int loop; |
| int sleep_ms = 0; |
| char *e; |
| |
| if (argc > 1) { |
| repeat = strtoi(argv[1], &e, 0); |
| if (*e) { |
| ccputs("Invalid repeat count\n"); |
| return EC_ERROR_INVAL; |
| } |
| } |
| |
| if (argc > 2) { |
| sleep_ms = strtoi(argv[2], &e, 0); |
| if (*e) { |
| ccputs("Invalid sleep ms\n"); |
| return EC_ERROR_INVAL; |
| } |
| } |
| |
| for (loop = 0; loop < repeat; loop++) { |
| print_battery_debug(); |
| |
| /* |
| * Running with a high repeat count will take so long the |
| * watchdog timer fires. So reset the watchdog timer each |
| * iteration. |
| */ |
| watchdog_reload(); |
| |
| if (sleep_ms) |
| msleep(sleep_ms); |
| } |
| |
| return EC_SUCCESS; |
| } |
| DECLARE_CONSOLE_COMMAND(battery, command_battery, |
| "<repeat_count> <sleep_ms>", |
| "Print battery info"); |
| |
| #ifdef CONFIG_BATTERY_CUT_OFF |
| int battery_is_cut_off(void) |
| { |
| return (battery_cutoff_state == BATTERY_CUTOFF_STATE_CUT_OFF); |
| } |
| |
| static void pending_cutoff_deferred(void) |
| { |
| int rv; |
| |
| rv = board_cut_off_battery(); |
| |
| if (rv == EC_RES_SUCCESS) { |
| CUTOFFPRINTS("succeeded."); |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_CUT_OFF; |
| } else { |
| CUTOFFPRINTS("failed!"); |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_NORMAL; |
| } |
| } |
| DECLARE_DEFERRED(pending_cutoff_deferred); |
| |
| static void clear_pending_cutoff(void) |
| { |
| if (extpower_is_present()) { |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_NORMAL; |
| hook_call_deferred(&pending_cutoff_deferred_data, -1); |
| } |
| } |
| DECLARE_HOOK(HOOK_AC_CHANGE, clear_pending_cutoff, HOOK_PRIO_DEFAULT); |
| |
| static enum ec_status battery_command_cutoff(struct host_cmd_handler_args *args) |
| { |
| const struct ec_params_battery_cutoff *p; |
| int rv; |
| |
| if (args->version == 1) { |
| p = args->params; |
| if (p->flags & EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN) { |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_PENDING; |
| CUTOFFPRINTS("at-shutdown is scheduled"); |
| return EC_RES_SUCCESS; |
| } |
| } |
| |
| rv = board_cut_off_battery(); |
| if (rv == EC_RES_SUCCESS) { |
| CUTOFFPRINTS("is successful."); |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_CUT_OFF; |
| } else { |
| CUTOFFPRINTS("has failed."); |
| } |
| |
| return rv; |
| } |
| DECLARE_HOST_COMMAND(EC_CMD_BATTERY_CUT_OFF, battery_command_cutoff, |
| EC_VER_MASK(0) | EC_VER_MASK(1)); |
| |
| static void check_pending_cutoff(void) |
| { |
| if (battery_cutoff_state == BATTERY_CUTOFF_STATE_PENDING) { |
| CPRINTS("Cutting off battery in %d second(s)", |
| CONFIG_BATTERY_CUTOFF_DELAY_US / SECOND); |
| hook_call_deferred(&pending_cutoff_deferred_data, |
| CONFIG_BATTERY_CUTOFF_DELAY_US); |
| } |
| } |
| DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, check_pending_cutoff, HOOK_PRIO_LAST); |
| |
| static int command_cutoff(int argc, char **argv) |
| { |
| int rv; |
| |
| if (argc > 1) { |
| if (!strcasecmp(argv[1], "at-shutdown")) { |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_PENDING; |
| return EC_SUCCESS; |
| } else { |
| return EC_ERROR_INVAL; |
| } |
| } |
| |
| rv = board_cut_off_battery(); |
| if (rv == EC_RES_SUCCESS) { |
| ccprints("Battery cut off"); |
| battery_cutoff_state = BATTERY_CUTOFF_STATE_CUT_OFF; |
| return EC_SUCCESS; |
| } |
| |
| return EC_ERROR_UNKNOWN; |
| } |
| DECLARE_CONSOLE_COMMAND(cutoff, command_cutoff, |
| "[at-shutdown]", |
| "Cut off the battery output"); |
| #else |
| int battery_is_cut_off(void) |
| { |
| return 0; /* Always return NOT cut off */ |
| } |
| #endif /* CONFIG_BATTERY_CUT_OFF */ |
| |
| #ifdef CONFIG_BATTERY_VENDOR_PARAM |
| static int console_command_battery_vendor_param(int argc, char **argv) |
| { |
| uint32_t param; |
| uint32_t value; |
| char *e; |
| int rv; |
| |
| if (argc < 2) |
| return EC_ERROR_INVAL; |
| |
| param = strtoi(argv[1], &e, 0); |
| if (*e) { |
| ccputs("Invalid param\n"); |
| return EC_ERROR_INVAL; |
| } |
| |
| if (argc > 2) { |
| value = strtoi(argv[2], &e, 0); |
| if (*e) { |
| ccputs("Invalid value\n"); |
| return EC_ERROR_INVAL; |
| } |
| rv = battery_set_vendor_param(param, value); |
| if (rv != EC_SUCCESS) |
| return rv; |
| } |
| |
| rv = battery_get_vendor_param(param, &value); |
| if (rv != EC_SUCCESS) |
| return rv; |
| |
| ccprintf("0x%08x\n", value); |
| return EC_SUCCESS; |
| } |
| DECLARE_CONSOLE_COMMAND(battparam, console_command_battery_vendor_param, |
| "<param> [value]", |
| "Get or set battery vendor parameters"); |
| |
| static enum ec_status |
| host_command_battery_vendor_param(struct host_cmd_handler_args *args) |
| { |
| int rv; |
| const struct ec_params_battery_vendor_param *p = args->params; |
| struct ec_response_battery_vendor_param *r = args->response; |
| |
| args->response_size = sizeof(*r); |
| |
| if (p->mode != BATTERY_VENDOR_PARAM_MODE_GET && |
| p->mode != BATTERY_VENDOR_PARAM_MODE_SET) |
| return EC_RES_INVALID_PARAM; |
| |
| if (p->mode == BATTERY_VENDOR_PARAM_MODE_SET) { |
| rv = battery_set_vendor_param(p->param, p->value); |
| if (rv != EC_SUCCESS) |
| return rv; |
| } |
| |
| rv = battery_get_vendor_param(p->param, &r->value); |
| return rv; |
| } |
| DECLARE_HOST_COMMAND(EC_CMD_BATTERY_VENDOR_PARAM, |
| host_command_battery_vendor_param, |
| EC_VER_MASK(0)); |
| #endif /* CONFIG_BATTERY_VENDOR_PARAM */ |
| |
| #ifdef CONFIG_BATTERY_V2 |
| #ifdef CONFIG_HOSTCMD_BATTERY_V2 |
| static void battery_update(enum battery_index i); |
| static enum ec_status |
| host_command_battery_get_static(struct host_cmd_handler_args *args) |
| { |
| const struct ec_params_battery_static_info *p = args->params; |
| struct ec_response_battery_static_info_v1 *bat; |
| |
| if (p->index < 0 || p->index >= CONFIG_BATTERY_COUNT) |
| return EC_RES_INVALID_PARAM; |
| bat = &battery_static[p->index]; |
| |
| battery_update(p->index); |
| if (args->version == 0) { |
| struct ec_response_battery_static_info *r = args->response; |
| |
| args->response_size = sizeof(*r); |
| r->design_capacity = bat->design_capacity; |
| r->design_voltage = bat->design_voltage; |
| r->cycle_count = bat->cycle_count; |
| |
| /* Truncate strings to reduced v0 size */ |
| memcpy(&r->manufacturer, &bat->manufacturer_ext, |
| sizeof(r->manufacturer)); |
| r->manufacturer[sizeof(r->manufacturer) - 1] = 0; |
| memcpy(&r->model, &bat->model_ext, sizeof(r->model)); |
| r->model[sizeof(r->model) - 1] = 0; |
| memcpy(&r->serial, &bat->serial_ext, sizeof(r->serial)); |
| r->serial[sizeof(r->serial) - 1] = 0; |
| memcpy(&r->type, &bat->type_ext, sizeof(r->type)); |
| r->type[sizeof(r->type) - 1] = 0; |
| } else { |
| /* v1 command stores the same data internally */ |
| struct ec_response_battery_static_info_v1 *r = args->response; |
| |
| args->response_size = sizeof(*r); |
| memcpy(r, bat, sizeof(*r)); |
| } |
| |
| return EC_RES_SUCCESS; |
| } |
| DECLARE_HOST_COMMAND(EC_CMD_BATTERY_GET_STATIC, |
| host_command_battery_get_static, |
| EC_VER_MASK(0) | EC_VER_MASK(1)); |
| |
| static enum ec_status |
| host_command_battery_get_dynamic(struct host_cmd_handler_args *args) |
| { |
| const struct ec_params_battery_dynamic_info *p = args->params; |
| struct ec_response_battery_dynamic_info *r = args->response; |
| |
| if (p->index < 0 || p->index >= CONFIG_BATTERY_COUNT) |
| return EC_RES_INVALID_PARAM; |
| |
| args->response_size = sizeof(*r); |
| memcpy(r, &battery_dynamic[p->index], sizeof(*r)); |
| |
| return EC_RES_SUCCESS; |
| } |
| DECLARE_HOST_COMMAND(EC_CMD_BATTERY_GET_DYNAMIC, |
| host_command_battery_get_dynamic, |
| EC_VER_MASK(0)); |
| #endif /* CONFIG_HOSTCMD_BATTERY_V2 */ |
| |
| #ifdef HAS_TASK_HOSTCMD |
| static void battery_update(enum battery_index i) |
| { |
| char *batt_str; |
| int *memmap_dcap = (int *)host_get_memmap(EC_MEMMAP_BATT_DCAP); |
| int *memmap_dvlt = (int *)host_get_memmap(EC_MEMMAP_BATT_DVLT); |
| int *memmap_ccnt = (int *)host_get_memmap(EC_MEMMAP_BATT_CCNT); |
| int *memmap_volt = (int *)host_get_memmap(EC_MEMMAP_BATT_VOLT); |
| int *memmap_rate = (int *)host_get_memmap(EC_MEMMAP_BATT_RATE); |
| int *memmap_cap = (int *)host_get_memmap(EC_MEMMAP_BATT_CAP); |
| int *memmap_lfcc = (int *)host_get_memmap(EC_MEMMAP_BATT_LFCC); |
| uint8_t *memmap_flags = host_get_memmap(EC_MEMMAP_BATT_FLAG); |
| |
| /* Smart battery serial number is 16 bits */ |
| batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_SERIAL); |
| memcpy(batt_str, battery_static[i].serial_ext, EC_MEMMAP_TEXT_MAX); |
| batt_str[EC_MEMMAP_TEXT_MAX - 1] = 0; |
| |
| /* Design Capacity of Full */ |
| *memmap_dcap = battery_static[i].design_capacity; |
| |
| /* Design Voltage */ |
| *memmap_dvlt = battery_static[i].design_voltage; |
| |
| /* Cycle Count */ |
| *memmap_ccnt = battery_static[i].cycle_count; |
| |
| /* Battery Manufacturer string */ |
| batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_MFGR); |
| memcpy(batt_str, battery_static[i].manufacturer_ext, |
| EC_MEMMAP_TEXT_MAX); |
| batt_str[EC_MEMMAP_TEXT_MAX - 1] = 0; |
| |
| /* Battery Model string */ |
| batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_MODEL); |
| memcpy(batt_str, battery_static[i].model_ext, EC_MEMMAP_TEXT_MAX); |
| batt_str[EC_MEMMAP_TEXT_MAX - 1] = 0; |
| |
| /* Battery Type string */ |
| batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_TYPE); |
| memcpy(batt_str, battery_static[i].type_ext, EC_MEMMAP_TEXT_MAX); |
| batt_str[EC_MEMMAP_TEXT_MAX - 1] = 0; |
| |
| *memmap_volt = battery_dynamic[i].actual_voltage; |
| *memmap_rate = battery_dynamic[i].actual_current; |
| *memmap_cap = battery_dynamic[i].remaining_capacity; |
| *memmap_lfcc = battery_dynamic[i].full_capacity; |
| *memmap_flags = battery_dynamic[i].flags; |
| } |
| |
| void battery_memmap_refresh(enum battery_index index) |
| { |
| if (*host_get_memmap(EC_MEMMAP_BATT_INDEX) == index) |
| battery_update(index); |
| } |
| |
| void battery_memmap_set_index(enum battery_index index) |
| { |
| if (*host_get_memmap(EC_MEMMAP_BATT_INDEX) == index) |
| return; |
| |
| *host_get_memmap(EC_MEMMAP_BATT_INDEX) = BATT_IDX_INVALID; |
| if (index < 0 || index >= CONFIG_BATTERY_COUNT) |
| return; |
| |
| battery_update(index); |
| *host_get_memmap(EC_MEMMAP_BATT_INDEX) = index; |
| } |
| |
| static void battery_init(void) |
| { |
| *host_get_memmap(EC_MEMMAP_BATT_INDEX) = BATT_IDX_INVALID; |
| *host_get_memmap(EC_MEMMAP_BATT_COUNT) = CONFIG_BATTERY_COUNT; |
| *host_get_memmap(EC_MEMMAP_BATTERY_VERSION) = 2; |
| |
| battery_memmap_set_index(BATT_IDX_MAIN); |
| } |
| DECLARE_HOOK(HOOK_INIT, battery_init, HOOK_PRIO_DEFAULT); |
| #endif /* HAS_TASK_HOSTCMD */ |
| #endif /* CONFIG_BATTERY_V2 */ |
| |
| void battery_compensate_params(struct batt_params *batt) |
| { |
| int numer, denom; |
| int *remain = &(batt->remaining_capacity); |
| int *full = &(batt->full_capacity); |
| |
| if ((batt->flags & BATT_FLAG_BAD_FULL_CAPACITY) || |
| (batt->flags & BATT_FLAG_BAD_REMAINING_CAPACITY)) |
| return; |
| |
| if (*remain <= 0 || *full <= 0) |
| return; |
| |
| /* full_factor is effectively disabled in powerd. */ |
| *full = *full * batt_full_factor / 100; |
| if (*remain > *full) |
| *remain = *full; |
| |
| /* |
| * Powerd uses the following equation to calculate display percentage: |
| * charge = 100 * remain / full |
| * display = 100 * (charge - shutdown_pct) / |
| * (full_factor - shutdown_pct) |
| * = 100 * ((100 * remain / full) - shutdown_pct) / |
| * (full_factor - shutdown_pct) |
| * = 100 * ((100 * remain) - (full * shutdown_pct)) / |
| * (full * (full_factor - shutdown_pct)) |
| * |
| * The unit of the following batt->display_charge is 0.1%. |
| */ |
| numer = 1000 * ((100 * *remain) - (*full * batt_host_shutdown_pct)); |
| denom = *full * (batt_host_full_factor - batt_host_shutdown_pct); |
| /* Rounding (instead of truncating) */ |
| batt->display_charge = (numer + denom / 2) / denom; |
| if (batt->display_charge < 0) |
| batt->display_charge = 0; |
| if (batt->display_charge > 1000) |
| batt->display_charge = 1000; |
| } |
| |
| __overridable void board_battery_compensate_params(struct batt_params *batt) |
| { |
| } |
| |
| __attribute__((weak)) int get_battery_manufacturer_name(char *dest, int size) |
| { |
| strzcpy(dest, "<unkn>", size); |
| return EC_SUCCESS; |
| } |
| |
| int battery_manufacturer_name(char *dest, int size) |
| { |
| return get_battery_manufacturer_name(dest, size); |
| } |