blob: 98d8642d469db216a9a33d1ddab49691a972166d [file] [log] [blame]
/*
* Google Battery Management System
*
* Copyright (C) 2018 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __GOOGLE_BMS_H_
#define __GOOGLE_BMS_H_
#include <linux/types.h>
#include "qmath.h"
struct device_node;
#define GBMS_CHG_TEMP_NB_LIMITS_MAX 10
#define GBMS_CHG_VOLT_NB_LIMITS_MAX 6
struct gbms_chg_profile {
const char *owner_name;
int temp_nb_limits;
s32 temp_limits[GBMS_CHG_TEMP_NB_LIMITS_MAX];
int volt_nb_limits;
s32 volt_limits[GBMS_CHG_VOLT_NB_LIMITS_MAX];
/* Array of constant current limits */
s32 *cccm_limits;
/* used to fill table */
u32 capacity_ma;
/* behavior */
u32 fv_uv_margin_dpct;
u32 cv_range_accuracy;
u32 cv_debounce_cnt;
u32 cv_update_interval;
u32 cv_tier_ov_cnt;
u32 cv_tier_switch_cnt;
u32 chg_last_tier_vpack_tolerance;
u32 chg_last_tier_dec_current;
u32 chg_last_tier_term_current;
s32 zero_ibat_offset;
/* taper step */
u32 fv_uv_resolution;
/* experimental */
u32 cv_otv_margin;
};
#define WLC_BPP_THRESHOLD_UV 700000
#define WLC_EPP_THRESHOLD_UV 1100000
#define FOREACH_CHG_EV_ADAPTER(S) \
S(UNKNOWN), \
S(USB), \
S(USB_SDP), \
S(USB_DCP), \
S(USB_CDP), \
S(USB_ACA), \
S(USB_C), \
S(USB_PD), \
S(USB_PD_DRP), \
S(USB_PD_PPS), \
S(USB_BRICKID), \
S(USB_HVDCP), \
S(USB_HVDCP3), \
S(USB_FLOAT), \
S(WLC), \
S(WLC_EPP), \
S(WLC_SPP), \
#define CHG_EV_ADAPTER_STRING(s) #s
#define _CHG_EV_ADAPTER_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
/* Enums will start with CHG_EV_ADAPTER_TYPE_ */
#define CHG_EV_ADAPTER_ENUM(e) \
_CHG_EV_ADAPTER_PRIMITIVE_CAT(CHG_EV_ADAPTER_TYPE_,e)
enum chg_ev_adapter_type_t {
FOREACH_CHG_EV_ADAPTER(CHG_EV_ADAPTER_ENUM)
};
enum gbms_msc_states_t {
MSC_NONE = 0,
MSC_SEED,
MSC_DSG,
MSC_LAST,
MSC_VSWITCH,
MSC_VOVER,
MSC_PULLBACK,
MSC_FAST,
MSC_TYPE,
MSC_DLY, /* in taper */
MSC_STEADY, /* in taper */
MSC_TIERCNTING, /* in taper */
MSC_RAISE, /* in taper */
MSC_WAIT, /* in taper */
MSC_RSTC, /* in taper */
MSC_NEXT, /* in taper */
MSC_NYET, /* in taper */
MSC_HEALTH,
MSC_STATES_COUNT,
};
union gbms_ce_adapter_details {
uint32_t v;
struct {
uint8_t ad_type;
uint8_t pad;
uint8_t ad_voltage;
uint8_t ad_amperage;
};
};
struct gbms_ce_stats {
uint16_t voltage_in;
uint16_t ssoc_in;
uint16_t cc_in;
uint16_t voltage_out;
uint16_t ssoc_out;
uint16_t cc_out;
};
struct ttf_tier_stat {
int16_t soc_in;
int cc_in;
int cc_total;
time_t avg_time;
};
struct gbms_ce_tier_stats {
int8_t temp_idx;
uint8_t vtier_idx;
int16_t soc_in; /* 8.8 */
uint16_t cc_in;
uint16_t cc_total;
uint32_t time_fast;
uint32_t time_taper;
uint32_t time_other;
int16_t temp_in;
int16_t temp_min;
int16_t temp_max;
int16_t ibatt_min;
int16_t ibatt_max;
uint16_t icl_min;
uint16_t icl_max;
int64_t icl_sum;
int64_t temp_sum;
int64_t ibatt_sum;
uint32_t sample_count;
uint16_t msc_cnt[MSC_STATES_COUNT];
uint32_t msc_elap[MSC_STATES_COUNT];
};
#define GBMS_STATS_TIER_COUNT 3
#define GBMS_SOC_STATS_LEN 101
/* time to full */
/* collected in charging event */
struct ttf_soc_stats {
int ti[GBMS_SOC_STATS_LEN]; /* charge tier at each soc */
int cc[GBMS_SOC_STATS_LEN]; /* coulomb count at each soc */
time_t elap[GBMS_SOC_STATS_LEN]; /* time spent at soc */
};
/* reference data for soc estimation */
struct ttf_adapter_stats {
u32 *soc_table;
u32 *elap_table;
int table_count;
};
/* updated when the device publish the charge stats
* NOTE: soc_stats and tier_stats are only valid for the given chg_profile
* since tier, coulumb count and elap time spent at each SOC depends on the
* maximum amount of current that can be pushed to the battery.
*/
struct batt_ttf_stats {
time_t ttf_fake;
struct ttf_soc_stats soc_ref; /* gold: soc->elap,cc */
int ref_temp_idx;
int ref_watts;
struct ttf_soc_stats soc_stats; /* rolling */
struct ttf_tier_stat tier_stats[GBMS_STATS_TIER_COUNT];
struct logbuffer *ttf_log;
};
struct gbms_charging_event {
union gbms_ce_adapter_details adapter_details;
/* profile used for this charge event */
const struct gbms_chg_profile *chg_profile;
/* charge event and tier tracking */
struct gbms_ce_stats charging_stats;
struct gbms_ce_tier_stats tier_stats[GBMS_STATS_TIER_COUNT];
struct gbms_ce_tier_stats health_stats;
/* soc tracking for time to full */
struct ttf_soc_stats soc_stats;
int last_soc;
time_t first_update;
time_t last_update;
uint32_t chg_sts_qual_time;
uint32_t chg_sts_delta_soc;
};
#define GBMS_CCCM_LIMITS(profile, ti, vi) \
profile->cccm_limits[(ti * profile->volt_nb_limits) + vi]
/* newgen charging */
#define GBMS_CS_FLAG_BUCK_EN (1 << 0)
#define GBMS_CS_FLAG_DONE (1 << 1)
#define GBMS_CS_FLAG_CC (1 << 2)
#define GBMS_CS_FLAG_CV (1 << 3)
#define GBMS_CS_FLAG_ILIM (1 << 4)
// This value must be greater than the threshold set in individual chargers
#define GBMS_ICL_MIN 100000 // 100 mA
union gbms_charger_state {
uint64_t v;
struct {
uint8_t flags;
uint8_t pad;
uint8_t chg_status;
uint8_t chg_type;
uint16_t vchrg;
uint16_t icl;
} f;
};
int gbms_init_chg_profile_internal(struct gbms_chg_profile *profile,
struct device_node *node, const char *owner_name);
#define gbms_init_chg_profile(p, n) \
gbms_init_chg_profile_internal(p, n, KBUILD_MODNAME)
void gbms_init_chg_table(struct gbms_chg_profile *profile, u32 capacity);
void gbms_free_chg_profile(struct gbms_chg_profile *profile);
void gbms_dump_raw_profile(const struct gbms_chg_profile *profile, int scale);
#define gbms_dump_chg_profile(profile) gbms_dump_raw_profile(profile, 1000)
/* newgen charging: charge profile */
int gbms_msc_temp_idx(const struct gbms_chg_profile *profile, int temp);
int gbms_msc_voltage_idx(const struct gbms_chg_profile *profile, int vbatt);
int gbms_msc_round_fv_uv(const struct gbms_chg_profile *profile,
int vtier, int fv_uv);
/* newgen charging: charger flags */
uint8_t gbms_gen_chg_flags(int chg_status, int chg_type);
/* debug/print */
const char *gbms_chg_type_s(int chg_type);
const char *gbms_chg_status_s(int chg_status);
const char *gbms_chg_ev_adapter_s(int adapter);
/* Votables */
#define VOTABLE_MSC_CHG_DISABLE "MSC_CHG_DISABLE"
#define VOTABLE_MSC_PWR_DISABLE "MSC_PWR_DISABLE"
#define VOTABLE_MSC_INTERVAL "MSC_INTERVAL"
#define VOTABLE_MSC_FCC "MSC_FCC"
#define VOTABLE_MSC_FV "MSC_FV"
#define VOTABLE_MSC_FORCE_5V "MSC_FORCE_5V"
/* Binned cycle count */
#define GBMS_CCBIN_BUCKET_COUNT 10
#if IS_ENABLED(CONFIG_QPNP_QG)
#undef GBMS_CCBIN_BUCKET_COUNT
#define GBMS_CCBIN_BUCKET_COUNT 8
#endif
#define GBMS_CCBIN_CSTR_SIZE (GBMS_CCBIN_BUCKET_COUNT * 6 + 2)
int gbms_cycle_count_sscan_bc(u16 *ccount, int bcnt, const char *buff);
int gbms_cycle_count_cstr_bc(char *buff, size_t size,
const u16 *ccount, int bcnt);
#define gbms_cycle_count_sscan(cc, buff) \
gbms_cycle_count_sscan_bc(cc, GBMS_CCBIN_BUCKET_COUNT, buff)
#define gbms_cycle_count_cstr(buff, size, cc) \
gbms_cycle_count_cstr_bc(buff, size, cc, GBMS_CCBIN_BUCKET_COUNT)
/* Time to full */
int ttf_soc_cstr(char *buff, int size, const struct ttf_soc_stats *soc_stats,
int start, int end);
int ttf_soc_estimate(time_t *res,
const struct batt_ttf_stats *stats,
const struct gbms_charging_event *ce_data,
qnum_t soc, qnum_t last);
void ttf_soc_init(struct ttf_soc_stats *dst);
int ttf_tier_cstr(char *buff, int size, const struct ttf_tier_stat *t_stat);
int ttf_tier_estimate(time_t *res,
const struct batt_ttf_stats *ttf_stats,
int temp_idx, int vbatt_idx,
int capacity, int full_capacity);
int ttf_stats_init(struct batt_ttf_stats *stats,
struct device *device,
int capacity_ma);
void ttf_stats_update(struct batt_ttf_stats *stats,
struct gbms_charging_event *ce_data,
bool force);
int ttf_stats_cstr(char *buff, int size, const struct batt_ttf_stats *stats,
bool verbose);
int ttf_stats_sscan(struct batt_ttf_stats *stats,
const char *buff, size_t size);
struct batt_ttf_stats *ttf_stats_dup(struct batt_ttf_stats *dst,
const struct batt_ttf_stats *src);
void ttf_log(const struct batt_ttf_stats *stats, const char *fmt, ...);
ssize_t ttf_dump_details(char *buf, int max_size,
const struct batt_ttf_stats *ttf_stats,
int last_soc);
/**
* GBMS Storage API
* The API provides functions to access to data stored in the persistent and
* semi-persistent storage of a device in a cross-platform and
* location-independent fashion. Clients in kernel and userspace use this
* directly and indirectly to retrieve battery serial number, cell chemistry
* type, cycle bin count, battery lifetime history and other battery related
* data.
*/
#define GBMS_STORAGE_ADDR_INVALID -1
#define GBMS_STORAGE_INDEX_INVALID -1
/* Battery Google Part Number */
#define GBMS_BGPN_LEN 10
/* Battery manufacturer info length */
#define GBMS_MINF_LEN 32
/* Battery device info length */
#define GBMS_DINF_LEN 32
/* Battery cycle count bin length */
#define GBMS_CNTB_LEN 16
/**
* Tags are u32 constants: hardcoding as hex since characters constants of more
* than one byte such as 'BGCE' are frown upon.
*/
typedef uint32_t gbms_tag_t;
enum gbms_tags {
GBMS_TAG_BGCE = 0x42474345,
GBMS_TAG_BCNT = 0x42434e54,
GBMS_TAG_BRES = 0x42524553,
GBMS_TAG_SNUM = 0x534e554d,
GBMS_TAG_HIST = 0x48495354,
GBMS_TAG_BRID = 0x42524944,
GBMS_TAG_DSNM = 0x44534e4d,
GBMS_TAG_MINF = 0x4d494e46,
GBMS_TAG_DINF = 0x44494e46,
GBMS_TAG_BGPN = 0x4247504e,
GBMS_TAG_CNTB = 0x434e5442,
GBMS_TAG_CELL = 0x43454c4c,
};
/**
* struct gbms_storage_desc - callbacks for a GBMS storage provider.
*
* Fields not used should be initialized with NULL. The provider name and the
* iter callback are optional but strongly recommended. The write, fetch, store
* and flush callbacks are optional, descriptors with a non NULL write/store
* callback should have a non NULL read/fetch callback.
*
* The iterator callback (iter) is used to list the tags stored in the provider
* and can be used to detect duplicates. The list of tags exported from iter
* can be expected to be static (i.e. tags can be enumerated once on
* registration).
*
* The read and write callbacks transfer the data associated with a tag. The
* calls must return -ENOENT when called with a tag that is not known to the
* provider, a negative number on every other error or the number of bytes
* read or written to the device. The tag lookup for the read and write
* callbacks must be very efficient (i.e. consider implementation that use hash
* or switch statements).
*
* Fetch and store callbacks are used to grant non-mediated access to a range
* of consecutive addresses in storage space. The implementation must return a
* negative number on error or the number of bytes transferred with the
* operation. Support caching of the tag data location requires non NULL fetch
* and not NULL info callbacks.
*
* The read_data and write_data callbacks transfer the data associated with an
* enumerator. The calls must return -ENOENT when called with a tag that is not
* known to the provider, a negative number on every other error or the number
* of bytes read or written to the device during data transfers.
*
* Clients can only access keys that are available on a device (i.e. clients
* cannot create new tags) and the API returns -ENOENT when trying to access a
* tag that is not available on a device, -EGAIN while the storage is not fully
* initialized.
*
* @iter: callback, return the tags known from this provider
* @info: callback, return address and size for tags (used for caching)
* @read: callback, read data from a tag
* @write: callback, write data to a tag
* @fetch: callback, read up to count data bytes from an address
* @store: callback, write up to count data bytes to an address
* @flush: callback, request a fush of data to permanent storage
* @read_data: callback, read the elements of an enumerations
* @write_data: callback, write to the elements of an enumeration
*/
struct gbms_storage_desc {
int (*iter)(int index, gbms_tag_t *tag, void *ptr);
int (*info)(gbms_tag_t tag, size_t *addr, size_t *size, void *ptr);
int (*read)(gbms_tag_t tag, void *data, size_t count, void *ptr);
int (*write)(gbms_tag_t tag, const void *data, size_t count, void *ptr);
int (*fetch)(void *data, size_t addr, size_t count, void *ptr);
int (*store)(const void *data, size_t addr, size_t count, void *ptr);
int (*flush)(bool force, void *ptr);
int (*read_data)(gbms_tag_t tag, void *data, size_t count, int idx,
void *ptr);
int (*write_data)(gbms_tag_t tag, const void *data, size_t count,
int idx, void *ptr);
};
struct gbms_storage_device;
#if IS_ENABLED(CONFIG_GOOGLE_BMS)
extern int gbms_storage_register(struct gbms_storage_desc *desc,
const char *name, void *ptr);
extern int gbms_storage_read(gbms_tag_t tag, void *data, size_t count);
extern int gbms_storage_write(gbms_tag_t tag, const void *data, size_t count);
extern int gbms_storage_read_data(gbms_tag_t tag, void *data, size_t count,
int idx);
extern int gbms_storage_write_data(gbms_tag_t tag, const void *data,
size_t count, int idx);
extern int gbms_storage_flush(gbms_tag_t tag);
extern int gbms_storage_flush_all(void);
/* standard device implementation that read data from an enumeration */
extern struct gbms_storage_device *gbms_storage_create_device(const char *name,
gbms_tag_t tag);
extern void gbms_storage_cleanup_device(struct gbms_storage_device *gdev);
#else
int gbms_storage_register(struct gbms_storage_desc *desc, const char *name,
void *ptr)
{
return -EINVAL;
}
int gbms_storage_read(gbms_tag_t tag, void *data, size_t count)
{
return -EINVAL;
}
int gbms_storage_write(gbms_tag_t tag, const void *data, size_t count)
{
return -EINVAL;
}
int gbms_storage_read_data(gbms_tag_t tag, void *data, size_t count, int idx)
{
return -EINVAL;
}
int gbms_storage_write_data(gbms_tag_t tag, const void *data, size_t count,
int idx)
{
return -EINVAL;
}
int gbms_storage_flush(gbms_tag_t tag)
{
return -EINVAL;
}
int gbms_storage_flush_all(void)
{
return -EINVAL;
}
struct gbms_storage_device *gbms_storage_create_device(const char *name,
gbms_tag_t tag)
{
return NULL;
}
void gbms_storage_cleanup_device(struct gbms_storage_device *gdev)
{
return;
}
#endif /* CONFIG_GOOGLE_BMS */
#endif /* __GOOGLE_BMS_H_ */