mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-11 18:35:28 +00:00
Export more battery information in LPC map
This data is used to populate the _BIF/_BIX packages in ACPI but it currently needs an EC command to retrieve that isn't easy to query in ACPI since it isn't using standard EC RAM. 1) Export these additional fields in init() state: - Design Capacity of Full - Design Voltage - Last Full Charge Capacity - Cycle Count - Manufacturer String - Model String - Serial Number String 2) Fix an issue where battery current was not reported when the battery was charging. 3) Remove the command interface so there is no duplication. BUG=chrome-os-partner:7734 TEST=using (not yet published) coreboot to read battery status via ACPI and verify that battery removal/insertion events are properly handled. Change-Id: If337aad3255e5b1a0f85168838f1dd86a32bbeb3 Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
/* Copyright (c) 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.
|
||||
*
|
||||
* Battery host commands for Chrome EC
|
||||
*/
|
||||
|
||||
|
||||
#include "host_command.h"
|
||||
#include "smart_battery.h"
|
||||
#include "battery.h"
|
||||
|
||||
static inline uint8_t hex2asc(uint8_t hex)
|
||||
{
|
||||
return hex + ((hex > 9) ? 'A' : '0');
|
||||
}
|
||||
|
||||
enum lpc_status battery_command_get_info(uint8_t *data)
|
||||
{
|
||||
struct lpc_response_battery_info *r =
|
||||
(struct lpc_response_battery_info *)data;
|
||||
int val;
|
||||
|
||||
if (battery_design_capacity(&val))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
r->design_capacity = val;
|
||||
r->design_capacity_warning = val * BATTERY_LEVEL_WARNING / 100;
|
||||
r->design_capacity_low = val * BATTERY_LEVEL_LOW / 100;
|
||||
|
||||
if (battery_full_charge_capacity(&val))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
r->last_full_charge_capacity = val;
|
||||
|
||||
if (battery_design_voltage(&val))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
r->design_output_voltage = val;
|
||||
|
||||
if (battery_cycle_count(&val))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
r->cycle_count = val;
|
||||
|
||||
return EC_LPC_RESULT_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_BATTERY_INFO,
|
||||
battery_command_get_info);
|
||||
|
||||
enum lpc_status battery_command_get_type(uint8_t *data)
|
||||
{
|
||||
struct lpc_response_battery_text *r =
|
||||
(struct lpc_response_battery_text *)data;
|
||||
|
||||
if (battery_device_chemistry(r->text, sizeof(r->text)))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
|
||||
return EC_LPC_RESULT_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_BATTERY_TYPE,
|
||||
battery_command_get_type);
|
||||
|
||||
enum lpc_status battery_command_get_model_number(uint8_t *data)
|
||||
{
|
||||
struct lpc_response_battery_text *r =
|
||||
(struct lpc_response_battery_text *)data;
|
||||
|
||||
if (battery_device_name(r->text, sizeof(r->text)))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
|
||||
return EC_LPC_RESULT_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_BATTERY_MODEL_NUMBER,
|
||||
battery_command_get_model_number);
|
||||
|
||||
enum lpc_status battery_command_get_serial_number(uint8_t *data)
|
||||
{
|
||||
struct lpc_response_battery_text *r =
|
||||
(struct lpc_response_battery_text *)data;
|
||||
int serial;
|
||||
|
||||
if (battery_serial_number(&serial))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
|
||||
/* Smart battery serial number is 16 bits */
|
||||
r->text[0] = hex2asc(0xf & (serial >> 12));
|
||||
r->text[1] = hex2asc(0xf & (serial >> 8));
|
||||
r->text[2] = hex2asc(0xf & (serial >> 4));
|
||||
r->text[3] = hex2asc(0xf & serial);
|
||||
r->text[4] = 0;
|
||||
|
||||
return EC_LPC_RESULT_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_BATTERY_SERIAL_NUMBER,
|
||||
battery_command_get_serial_number);
|
||||
|
||||
enum lpc_status battery_command_get_oem(uint8_t *data)
|
||||
{
|
||||
struct lpc_response_battery_text *r =
|
||||
(struct lpc_response_battery_text *)data;
|
||||
|
||||
if (battery_manufacturer_name(r->text, sizeof(r->text)))
|
||||
return EC_LPC_RESULT_ERROR;
|
||||
|
||||
return EC_LPC_RESULT_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_BATTERY_OEM,
|
||||
battery_command_get_oem);
|
||||
@@ -16,8 +16,7 @@ common-$(CONFIG_LPC)+=port80.o host_event_commands.o
|
||||
common-$(CONFIG_POWER_LED)+=power_led.o
|
||||
common-$(CONFIG_PSTORE)+=pstore_commands.o
|
||||
common-$(CONFIG_PWM)+=pwm_commands.o
|
||||
common-$(CONFIG_SMART_BATTERY)+=smart_battery.o charge_state.o \
|
||||
battery_commands.o
|
||||
common-$(CONFIG_SMART_BATTERY)+=smart_battery.o charge_state.o
|
||||
common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o
|
||||
common-$(CONFIG_TASK_HOSTCMD)+=host_command.o
|
||||
common-$(CONFIG_TASK_I8042CMD)+=i8042.o keyboard.o
|
||||
|
||||
@@ -101,6 +101,53 @@ static inline int get_ac(void)
|
||||
return gpio_get_level(GPIO_AC_PRESENT);
|
||||
}
|
||||
|
||||
/* Battery information used to fill ACPI _BIF and/or _BIX */
|
||||
static void update_battery_info(void)
|
||||
{
|
||||
char *batt_str;
|
||||
int batt_serial;
|
||||
|
||||
/* Design Capacity of Full */
|
||||
battery_design_capacity((int *)(lpc_get_memmap_range() +
|
||||
EC_LPC_MEMMAP_BATT_DCAP));
|
||||
|
||||
/* Design Voltage */
|
||||
battery_design_voltage((int *)(lpc_get_memmap_range() +
|
||||
EC_LPC_MEMMAP_BATT_DVLT));
|
||||
|
||||
/* Last Full Charge Capacity */
|
||||
battery_full_charge_capacity((int *)(lpc_get_memmap_range() +
|
||||
EC_LPC_MEMMAP_BATT_LFCC));
|
||||
|
||||
/* Cycle Count */
|
||||
battery_cycle_count((int *)(lpc_get_memmap_range() +
|
||||
EC_LPC_MEMMAP_BATT_CCNT));
|
||||
|
||||
/* Battery Manufacturer string */
|
||||
batt_str = (char *)(lpc_get_memmap_range() + EC_LPC_MEMMAP_BATT_MFGR);
|
||||
memset(batt_str, 0, EC_LPC_MEMMAP_TEXT_MAX);
|
||||
battery_manufacturer_name(batt_str, EC_LPC_MEMMAP_TEXT_MAX);
|
||||
|
||||
/* Battery Model string */
|
||||
batt_str = (char *)(lpc_get_memmap_range() + EC_LPC_MEMMAP_BATT_MODEL);
|
||||
memset(batt_str, 0, EC_LPC_MEMMAP_TEXT_MAX);
|
||||
battery_device_name(batt_str, EC_LPC_MEMMAP_TEXT_MAX);
|
||||
|
||||
/* Battery Type string */
|
||||
batt_str = (char *)(lpc_get_memmap_range() + EC_LPC_MEMMAP_BATT_TYPE);
|
||||
battery_device_chemistry(batt_str, EC_LPC_MEMMAP_TEXT_MAX);
|
||||
|
||||
/* Smart battery serial number is 16 bits */
|
||||
batt_str = (char *)(lpc_get_memmap_range() + EC_LPC_MEMMAP_BATT_SERIAL);
|
||||
memset(batt_str, 0, EC_LPC_MEMMAP_TEXT_MAX);
|
||||
if (battery_serial_number(&batt_serial) == 0) {
|
||||
*batt_str++ = hex2asc(0xf & (batt_serial >> 12));
|
||||
*batt_str++ = hex2asc(0xf & (batt_serial >> 8));
|
||||
*batt_str++ = hex2asc(0xf & (batt_serial >> 4));
|
||||
*batt_str++ = hex2asc(0xf & batt_serial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Common handler for charging states.
|
||||
* This handler gets battery charging parameters, charger state, ac state,
|
||||
* and timestamp. It also fills memory map and issues power events on state
|
||||
@@ -171,7 +218,8 @@ static int state_common(struct power_state_context *ctx)
|
||||
if (rv)
|
||||
curr->error |= F_BATTERY_CURRENT;
|
||||
/* Memory mapped value: discharge rate */
|
||||
*ctx->memmap_batt_rate = batt->current < 0 ? -batt->current : 0;
|
||||
*ctx->memmap_batt_rate = batt->current < 0 ?
|
||||
-batt->current : batt->current;
|
||||
|
||||
rv = battery_desired_voltage(&batt->desired_voltage);
|
||||
if (rv)
|
||||
@@ -255,6 +303,13 @@ static enum power_state state_init(struct power_state_context *ctx)
|
||||
if (ctx->curr.error)
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
/* Update static battery info */
|
||||
update_battery_info();
|
||||
|
||||
/* Send battery event to host */
|
||||
lpc_set_host_events(EC_LPC_HOST_EVENT_MASK(
|
||||
EC_LPC_HOST_EVENT_BATTERY));
|
||||
|
||||
return PWR_STATE_IDLE;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,16 +38,25 @@
|
||||
|
||||
#define EC_LPC_ADDR_MEMMAP 0x900
|
||||
#define EC_LPC_MEMMAP_SIZE 256
|
||||
#define EC_LPC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */
|
||||
|
||||
/* The offset address of each type of data in mapped memory. */
|
||||
#define EC_LPC_MEMMAP_TEMP_SENSOR 0x00
|
||||
#define EC_LPC_MEMMAP_FAN 0x10
|
||||
#define EC_LPC_MEMMAP_BATT_VOLT 0x20
|
||||
#define EC_LPC_MEMMAP_BATT_RATE 0x24
|
||||
#define EC_LPC_MEMMAP_BATT_CAP 0x28
|
||||
#define EC_LPC_MEMMAP_BATT_FLAG 0x2c
|
||||
#define EC_LPC_MEMMAP_SWITCHES 0x30
|
||||
#define EC_LPC_MEMMAP_HOST_EVENTS 0x34
|
||||
#define EC_LPC_MEMMAP_BATT_VOLT 0x40 /* Battery Present Voltage */
|
||||
#define EC_LPC_MEMMAP_BATT_RATE 0x44 /* Battery Present Rate */
|
||||
#define EC_LPC_MEMMAP_BATT_CAP 0x48 /* Battery Remaining Capacity */
|
||||
#define EC_LPC_MEMMAP_BATT_FLAG 0x4c /* Battery State, defined below */
|
||||
#define EC_LPC_MEMMAP_BATT_DCAP 0x50 /* Battery Design Capacity */
|
||||
#define EC_LPC_MEMMAP_BATT_DVLT 0x54 /* Battery Design Voltage */
|
||||
#define EC_LPC_MEMMAP_BATT_LFCC 0x58 /* Battery Last Full Charge Capacity */
|
||||
#define EC_LPC_MEMMAP_BATT_CCNT 0x5c /* Battery Cycle Count */
|
||||
#define EC_LPC_MEMMAP_BATT_MFGR 0x60 /* Battery Manufacturer String */
|
||||
#define EC_LPC_MEMMAP_BATT_MODEL 0x68 /* Battery Model Number String */
|
||||
#define EC_LPC_MEMMAP_BATT_SERIAL 0x70 /* Battery Serial Number String */
|
||||
#define EC_LPC_MEMMAP_BATT_TYPE 0x78 /* Battery Type String */
|
||||
|
||||
/* Battery bit flags at EC_LPC_MEMMAP_BATT_FLAG. */
|
||||
#define EC_BATT_FLAG_AC_PRESENT 0x01
|
||||
@@ -398,45 +407,6 @@ struct lpc_response_thermal_get_threshold {
|
||||
/* Toggling automatic fan control */
|
||||
#define EC_LPC_COMMAND_THERMAL_AUTO_FAN_CTRL 0x52
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Battery commands */
|
||||
|
||||
/* Maximum asciiz length of battery text data */
|
||||
#define EC_LPC_BATT_TEXT_MAX 32
|
||||
|
||||
/* Get battery info */
|
||||
#define EC_LPC_COMMAND_BATTERY_INFO 0x60
|
||||
struct lpc_response_battery_info {
|
||||
uint32_t design_capacity;
|
||||
uint32_t last_full_charge_capacity;
|
||||
uint32_t design_output_voltage;
|
||||
uint32_t design_capacity_warning;
|
||||
uint32_t design_capacity_low;
|
||||
uint32_t cycle_count;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Following 4 battery commands use the same response data type
|
||||
* BATTERY_TYPE
|
||||
* BATTERY_MODEL_NUMBER
|
||||
* BATTERY_MODEL_NUMBER
|
||||
* BATTERY_SERIAL_NUMBER
|
||||
*/
|
||||
struct lpc_response_battery_text {
|
||||
char text[EC_LPC_BATT_TEXT_MAX];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Get battery chemistry */
|
||||
#define EC_LPC_COMMAND_BATTERY_TYPE 0x61
|
||||
|
||||
/* Get battery model number */
|
||||
#define EC_LPC_COMMAND_BATTERY_MODEL_NUMBER 0x62
|
||||
|
||||
/* Get battery serial number */
|
||||
#define EC_LPC_COMMAND_BATTERY_SERIAL_NUMBER 0x63
|
||||
|
||||
/* Get battery OEM name */
|
||||
#define EC_LPC_COMMAND_BATTERY_OEM 0x64
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Host event commands */
|
||||
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
#define DIV_ROUND_UP(x, y) (((x) + ((y) - 1)) / (y))
|
||||
#define DIV_ROUND_NEAREST(x, y) (((x) + ((y) / 2)) / (y))
|
||||
|
||||
static inline uint8_t hex2asc(uint8_t hex)
|
||||
{
|
||||
return hex + ((hex > 9) ? 'A' : '0');
|
||||
}
|
||||
|
||||
/* Standard library functions */
|
||||
int atoi(const char *nptr);
|
||||
int isdigit(int c);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lpc_commands.h"
|
||||
#include "battery.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
/* Don't use a macro where an inline will do... */
|
||||
@@ -243,6 +244,21 @@ uint32_t read_mapped_mem32(uint8_t offset)
|
||||
}
|
||||
|
||||
|
||||
int read_mapped_string(uint8_t offset, char *buf)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < EC_LPC_MEMMAP_TEXT_MAX; c++) {
|
||||
buf[c] = inb(EC_LPC_ADDR_MEMMAP + offset + c);
|
||||
if (buf[c] == 0)
|
||||
return c;
|
||||
}
|
||||
|
||||
buf[EC_LPC_MEMMAP_TEXT_MAX-1] = 0;
|
||||
return EC_LPC_MEMMAP_TEXT_MAX;
|
||||
}
|
||||
|
||||
|
||||
void print_help(const char *prog)
|
||||
{
|
||||
printf("Usage: %s <command> [params]\n\n", prog);
|
||||
@@ -1171,52 +1187,41 @@ int cmd_switches(int argc, char *argv[])
|
||||
|
||||
int cmd_battery(int argc, char *argv[])
|
||||
{
|
||||
struct lpc_response_battery_info batt_info;
|
||||
struct lpc_response_battery_text batt_text;
|
||||
char batt_text[EC_LPC_MEMMAP_TEXT_MAX];
|
||||
int rv;
|
||||
|
||||
printf("Battery info:\n");
|
||||
|
||||
rv = ec_command(EC_LPC_COMMAND_BATTERY_OEM,
|
||||
NULL, 0, &batt_text, sizeof(batt_text));
|
||||
rv = read_mapped_string(EC_LPC_MEMMAP_BATT_MFGR, batt_text);
|
||||
if (rv)
|
||||
return rv;
|
||||
printf(" OEM name: %s\n", batt_text.text);
|
||||
printf(" OEM name: %s\n", batt_text);
|
||||
|
||||
rv = ec_command(EC_LPC_COMMAND_BATTERY_MODEL_NUMBER,
|
||||
NULL, 0, &batt_text, sizeof(batt_text));
|
||||
rv = read_mapped_string(EC_LPC_MEMMAP_BATT_MODEL, batt_text);
|
||||
if (rv)
|
||||
return rv;
|
||||
printf(" Model number: %s\n", batt_text.text);
|
||||
printf(" Model number: %s\n", batt_text);
|
||||
|
||||
rv = ec_command(EC_LPC_COMMAND_BATTERY_TYPE,
|
||||
NULL, 0, &batt_text, sizeof(batt_text));
|
||||
rv = read_mapped_string(EC_LPC_MEMMAP_BATT_TYPE, batt_text);
|
||||
if (rv)
|
||||
return rv;
|
||||
printf(" Chemistry: %s\n", batt_text.text);
|
||||
printf(" Chemistry : %s\n", batt_text);
|
||||
|
||||
rv = ec_command(EC_LPC_COMMAND_BATTERY_SERIAL_NUMBER,
|
||||
NULL, 0, &batt_text, sizeof(batt_text));
|
||||
rv = read_mapped_string(EC_LPC_MEMMAP_BATT_SERIAL, batt_text);
|
||||
if (rv)
|
||||
return rv;
|
||||
printf(" Serial number: %s\n", batt_text.text);
|
||||
printf(" Serial number: %s\n", batt_text);
|
||||
|
||||
rv = ec_command(EC_LPC_COMMAND_BATTERY_INFO,
|
||||
NULL, 0, &batt_info, sizeof(batt_info));
|
||||
if (rv)
|
||||
return rv;
|
||||
printf(" Design capacity: %u mAh\n",
|
||||
batt_info.design_capacity);
|
||||
read_mapped_mem32(EC_LPC_MEMMAP_BATT_DCAP));
|
||||
printf(" Last full charge: %u mAh\n",
|
||||
batt_info.last_full_charge_capacity);
|
||||
read_mapped_mem32(EC_LPC_MEMMAP_BATT_LFCC));
|
||||
printf(" Design output voltage %u mV\n",
|
||||
batt_info.design_output_voltage);
|
||||
read_mapped_mem32(EC_LPC_MEMMAP_BATT_DVLT));
|
||||
printf(" Design capacity warning %u mAh\n",
|
||||
batt_info.design_capacity_warning);
|
||||
read_mapped_mem32(EC_LPC_MEMMAP_BATT_DCAP) *
|
||||
BATTERY_LEVEL_WARNING / 100);
|
||||
printf(" Design capacity low %u mAh\n",
|
||||
batt_info.design_capacity_low);
|
||||
read_mapped_mem32(EC_LPC_MEMMAP_BATT_DCAP) *
|
||||
BATTERY_LEVEL_LOW / 100);
|
||||
printf(" Cycle count %u\n",
|
||||
batt_info.cycle_count);
|
||||
read_mapped_mem32(EC_LPC_MEMMAP_BATT_CCNT));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user