diff options
author | PixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com> | 2024-02-25 18:59:27 -0800 |
---|---|---|
committer | SecurityBot <android-nexus-securitybot@system.gserviceaccount.com> | 2024-02-25 18:59:28 -0800 |
commit | 0dc90bee72facdd7959eae79864663cf8f683b85 (patch) | |
tree | b3110e88fa9cbd2d0b2df163b1bf2a6f2bff17f5 | |
parent | 1735a681469d120473b7fac4642619db74628056 (diff) | |
parent | e87ffcff3d1816a2129eacbf59aa48040ce9f5dd (diff) | |
download | bms-android-gs-raviole-5.10-android15-dp.tar.gz |
Merge android13-gs-pixel-5.10-24Q2 into android13-gs-pixel-5.10android-15-beta-1_r0.5android-gs-raviole-5.10-android15-dp
SBMerger: 605678113
Change-Id: I445440a3e3c82acffb1bde7b129e4dc83071529d
Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
-rw-r--r-- | Documentation/ABI/testing/sysfs-class-power | 9 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | google_bms.c | 24 | ||||
-rw-r--r-- | google_bms.h | 4 | ||||
-rw-r--r-- | max1720x_battery.c | 152 | ||||
-rw-r--r-- | max1720x_battery.h | 46 | ||||
-rw-r--r-- | max_m5.c | 11 | ||||
-rw-r--r-- | maxfg_logging.c | 277 | ||||
-rw-r--r-- | maxfg_logging.h | 57 | ||||
-rw-r--r-- | p9221_charger.c | 1 |
10 files changed, 548 insertions, 34 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power new file mode 100644 index 0000000..04d0edd --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-power @@ -0,0 +1,9 @@ +What: /sys/class/power_supply/maxfg/fg_learning_events +Date: Feb 2024 +Contact: apelosi@google.com +Description: + Report a snapshot of fuel gauge registers captured during + each learning event. Write 0 to clear the events. + + Access: Read/Write + Valid values: Represented as string
\ No newline at end of file @@ -101,6 +101,7 @@ max77759-objs += max77759_maxq.o obj-$(CONFIG_MAX1720X_BATTERY) += max1720x-battery.o max1720x-battery-objs += max1720x_battery.o max1720x-battery-objs += max1720x_outliers.o +max1720x-battery-objs += maxfg_logging.o max1720x-battery-objs += max_m5.o # OVP diff --git a/google_bms.c b/google_bms.c index 3e78080..fc2f171 100644 --- a/google_bms.c +++ b/google_bms.c @@ -717,6 +717,30 @@ void gbms_logbuffer_prlog(struct logbuffer *log, int level, int debug_no_logbuff } EXPORT_SYMBOL_GPL(gbms_logbuffer_prlog); +void gbms_logbuffer_devlog(struct logbuffer *log, struct device *dev, int level, + int debug_no_logbuffer, int debug_printk_prlog, + const char *f, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, f); + + vaf.fmt = f; + vaf.va = &args; + + if (!debug_no_logbuffer) + logbuffer_vlog(log, f, args); + + if (level <= debug_printk_prlog) + dev_printk_emit(level, dev, "%s %s: %pV", + dev_driver_string(dev), + dev_name(dev), &vaf); + + va_end(args); +} +EXPORT_SYMBOL_GPL(gbms_logbuffer_devlog); + bool chg_state_is_disconnected(const union gbms_charger_state *chg_state) { return ((chg_state->f.flags & GBMS_CS_FLAG_BUCK_EN) == 0) && diff --git a/google_bms.h b/google_bms.h index 83fc9ad..fec3346 100644 --- a/google_bms.h +++ b/google_bms.h @@ -456,6 +456,10 @@ __printf(5,6) void gbms_logbuffer_prlog(struct logbuffer *log, int level, int debug_no_logbuffer, int debug_printk_prlog, const char *f, ...); +void gbms_logbuffer_devlog(struct logbuffer *log, struct device *dev, int level, + int debug_no_logbuffer, int debug_printk_prlog, + const char *f, ...); + /* debug/print */ const char *gbms_chg_type_s(int chg_type); const char *gbms_chg_status_s(int chg_status); diff --git a/max1720x_battery.c b/max1720x_battery.c index d27896e..a5601e1 100644 --- a/max1720x_battery.c +++ b/max1720x_battery.c @@ -35,6 +35,7 @@ #include "gbms_power_supply.h" #include "google_bms.h" #include "max1720x_battery.h" +#include "maxfg_logging.h" #include <linux/debugfs.h> @@ -278,6 +279,9 @@ struct max1720x_chip { /* Current Offset */ bool current_offset_done; + + /* buffer for recording learning history */ + struct maxfg_capture_buf cb_lh; }; #define MAX1720_EMPTY_VOLTAGE(profile, temp, cycle) \ @@ -308,41 +312,7 @@ static bool max17x0x_reglog_init(struct max1720x_chip *chip) /* TODO: split between NV and Volatile? */ -static const struct max17x0x_reg * max17x0x_find_by_index(struct max17x0x_regtags *tags, - int index) -{ - if (index < 0 || !tags || index >= tags->max) - return NULL; - - return &tags->map[index]; -} - -static const struct max17x0x_reg * max17x0x_find_by_tag(struct max17x0x_regmap *map, - enum max17x0x_reg_tags tag) -{ - return max17x0x_find_by_index(&map->regtags, tag); -} - -static inline int max17x0x_reg_read(struct max17x0x_regmap *map, - enum max17x0x_reg_tags tag, - u16 *val) -{ - const struct max17x0x_reg *reg; - unsigned int tmp; - int rtn; - - reg = max17x0x_find_by_tag(map, tag); - if (!reg) - return -EINVAL; - - rtn = regmap_read(map->regmap, reg->reg, &tmp); - if (rtn) - pr_err("Failed to read %x\n", reg->reg); - else - *val = tmp; - return rtn; -} /* ------------------------------------------------------------------------- */ @@ -1142,6 +1112,36 @@ static ssize_t rc_switch_enable_show(struct device *dev, static const DEVICE_ATTR_RW(rc_switch_enable); + +static ssize_t fg_learning_events_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = container_of(dev, struct power_supply, dev); + struct max1720x_chip *chip = power_supply_get_drvdata(psy); + + return maxfg_show_captured_buffer(&chip->cb_lh, buf, PAGE_SIZE); +} + +static ssize_t fg_learning_events_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct power_supply *psy = container_of(dev, struct power_supply, dev); + struct max1720x_chip *chip = power_supply_get_drvdata(psy); + int value, ret; + + ret = kstrtoint(buf, 0, &value); + if (ret < 0) + return ret; + + if (value == 0) + maxfg_clear_capture_buf(&chip->cb_lh); + + return count; +} + +static DEVICE_ATTR_RW(fg_learning_events); + /* lsb 1/256, race with max1720x_model_work() */ static int max1720x_get_capacity_raw(struct max1720x_chip *chip, u16 *data) { @@ -2272,6 +2272,49 @@ static int max1720x_current_offset_fix(struct max1720x_chip *chip) return ret; } +static int max1720x_monitor_log_learning(struct max1720x_chip *chip, bool force) +{ + const bool seed = !chip->cb_lh.latest_entry; + bool log_it; + char *buf; + int ret; + + /* do nothing if no changes on dpacc/dqacc or relaxation */ + log_it = force || seed || + maxfg_ce_relaxed(&chip->regmap, MAX_M5_FSTAT_RELDT | MAX_M5_FSTAT_RELDT2, + (u16 *)chip->cb_lh.latest_entry); + if (!log_it) + return 0; + + ret = maxfg_capture_registers(&chip->cb_lh); + if (ret < 0) { + dev_dbg(chip->dev, "cannot read learning parameters (%d)\n", ret); + return ret; + } + + /* no need to log at boot */ + if (seed) + return 0; + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = maxfg_capture_to_cstr(&chip->cb_lh.config, + (u16 *)chip->cb_lh.latest_entry, + buf, PAGE_SIZE); + if (ret > 0) + gbms_logbuffer_devlog(chip->monitor_log, chip->dev, + LOGLEVEL_INFO, 0, LOGLEVEL_INFO, + "learn %s", buf); + + kfree(buf); + + kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); + + return 0; +} + static int max1720x_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -2309,6 +2352,9 @@ static int max1720x_get_property(struct power_supply *psy, if (err == POWER_SUPPLY_STATUS_FULL) batt_ce_start(&chip->cap_estimate, chip->cap_estimate.cap_tsettle); + /* check for relaxation event and log it */ + max1720x_monitor_log_learning(chip, false); + /* return data ok */ err = 0; break; @@ -2940,6 +2986,7 @@ static bool max1720x_fg_irq_storm_check(struct max1720x_chip *chip) return storm; } + static irqreturn_t max1720x_fg_irq_thread_fn(int irq, void *obj) { struct max1720x_chip *chip = (struct max1720x_chip *)obj; @@ -3104,6 +3151,7 @@ static irqreturn_t max1720x_fg_irq_thread_fn(int irq, void *obj) if (storm) { pr_debug("Force power_supply_change in storm\n"); } else { + max1720x_monitor_log_learning(chip, false); max1720x_monitor_log_data(chip, false); if (chip->gauge_type == MAX_M5_GAUGE_TYPE) max_m5_check_recal_state(chip->model_data, @@ -3830,6 +3878,17 @@ static int debug_fake_battery_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(debug_fake_battery_fops, NULL, debug_fake_battery_set, "%llu\n"); + +static int max1720x_log_learn_set(void *data, u64 val) +{ + struct max1720x_chip *chip = data; + + max1720x_monitor_log_learning(chip, true); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debug_log_learn_fops, NULL, max1720x_log_learn_set, "%llu\n"); + + static void max17x0x_reglog_dump(struct max17x0x_reglog *regs, size_t size, char *buff) @@ -4231,6 +4290,7 @@ static ssize_t act_impedance_show(struct device *dev, static const DEVICE_ATTR_RW(act_impedance); + static int max17x0x_init_sysfs(struct max1720x_chip *chip) { struct dentry *de; @@ -4252,6 +4312,7 @@ static int max17x0x_init_sysfs(struct max1720x_chip *chip) debugfs_create_file("fake_battery", 0400, de, chip, &debug_fake_battery_fops); debugfs_create_file("batt_id", 0600, de, chip, &debug_batt_id_fops); debugfs_create_file("force_psy_update", 0600, de, chip, &debug_force_psy_update_fops); + debugfs_create_file("log_learn", 0400, de, chip, &debug_log_learn_fops); if (chip->regmap.reglog) debugfs_create_file("regmap_writes", 0440, de, @@ -6164,6 +6225,26 @@ void *max1720x_get_model_data(struct i2c_client *client) return chip ? chip->model_data : NULL; } + +static int max1720x_init_fg_capture(struct max1720x_chip *chip) +{ + struct device *dev = &chip->psy->dev; + int ret; + + /* Logging FG Learning */ + maxfg_init_fg_learn_capture_config(&chip->cb_lh.config, + &chip->regmap, &chip->regmap); + ret = maxfg_alloc_capture_buf(&chip->cb_lh, MAX_FG_LEARN_PARAM_MAX_HIST); + if (ret < 0) + return -ENOMEM; + + ret = device_create_file(dev, &dev_attr_fg_learning_events); + if (ret) + dev_err(dev, "Failed to create fg_learning_params attribute\n"); + + return ret; +} + static int max1720x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -6338,6 +6419,7 @@ static int max1720x_probe(struct i2c_client *client, chip->reg_prop_capacity_raw = (reg) ? reg->reg : MAX1720X_REPSOC; max17x0x_init_sysfs(chip); + max1720x_init_fg_capture(chip); INIT_DELAYED_WORK(&chip->cap_estimate.settle_timer, batt_ce_capacityfiltered_work); @@ -6381,6 +6463,8 @@ static int max1720x_remove(struct i2c_client *client) if (chip->secondary) i2c_unregister_device(chip->secondary); + + maxfg_free_capture_buf(&chip->cb_lh); wakeup_source_unregister(chip->get_prop_ws); return 0; diff --git a/max1720x_battery.h b/max1720x_battery.h index 93e8f3f..403b992 100644 --- a/max1720x_battery.h +++ b/max1720x_battery.h @@ -67,6 +67,17 @@ enum max17x0x_reg_tags { MAX17X0X_TAG_BCEA, MAX17X0X_TAG_rset, MAX17X0X_TAG_BRES, + + MAXFG_TAG_fcnom, + MAXFG_TAG_dpacc, + MAXFG_TAG_dqacc, + MAXFG_TAG_fcrep, + MAXFG_TAG_repsoc, + MAXFG_TAG_msoc, + MAXFG_TAG_learn, + MAXFG_TAG_rcomp0, + MAXFG_TAG_tempco, + MAXFG_TAG_fstat, }; enum max17x0x_reg_types { @@ -139,6 +150,41 @@ struct max17x0x_regmap { struct max17x0x_reglog *reglog; }; +static inline const struct max17x0x_reg *max17x0x_find_by_index(struct max17x0x_regtags *tags, + int index) +{ + if (index < 0 || !tags || index >= tags->max) + return NULL; + + return &tags->map[index]; +} + +static inline const struct max17x0x_reg *max17x0x_find_by_tag(struct max17x0x_regmap *map, + enum max17x0x_reg_tags tag) +{ + return max17x0x_find_by_index(&map->regtags, tag); +} + +static inline int max17x0x_reg_read(struct max17x0x_regmap *map, + enum max17x0x_reg_tags tag, + u16 *val) +{ + const struct max17x0x_reg *reg; + unsigned int tmp; + int rtn; + + reg = max17x0x_find_by_tag(map, tag); + if (!reg) + return -EINVAL; + + rtn = regmap_read(map->regmap, reg->reg, &tmp); + if (rtn == 0) + *val = tmp; + + return rtn; +} + + int max1720x_get_capacity(struct i2c_client *client, int *iic_raw); int max1720x_get_voltage_now(struct i2c_client *client, int *iic_raw); int max17x0x_sw_reset(struct i2c_client *client); @@ -1594,6 +1594,17 @@ const struct max17x0x_reg max_m5[] = { [MAX17X0X_TAG_curr] = { ATOM_INIT_REG16(MAX_M5_CURRENT)}, [MAX17X0X_TAG_mcap] = { ATOM_INIT_REG16(MAX_M5_MIXCAP)}, [MAX17X0X_TAG_vfsoc] = { ATOM_INIT_REG16(MAX_M5_VFSOC)}, + + [MAXFG_TAG_tempco] = { ATOM_INIT_REG16(MAX_M5_TEMPCO)}, + [MAXFG_TAG_rcomp0] = { ATOM_INIT_REG16(MAX_M5_RCOMP0)}, + [MAXFG_TAG_fcnom] = { ATOM_INIT_REG16(MAX_M5_FULLCAPNOM)}, + [MAXFG_TAG_fcrep] = { ATOM_INIT_REG16(MAX_M5_FULLCAPREP)}, + [MAXFG_TAG_repsoc] = { ATOM_INIT_REG16(MAX_M5_REPSOC)}, + [MAXFG_TAG_msoc] = { ATOM_INIT_REG16(MAX_M5_MIXSOC)}, + [MAXFG_TAG_learn] = { ATOM_INIT_REG16(MAX_M5_LEARNCFG)}, + [MAXFG_TAG_fstat] = { ATOM_INIT_REG16(MAX_M5_FSTAT)}, + [MAXFG_TAG_dqacc] = { ATOM_INIT_REG16(MAX_M5_DQACC)}, + [MAXFG_TAG_dpacc] = { ATOM_INIT_REG16(MAX_M5_DPACC)}, }; int max_m5_regmap_init(struct max17x0x_regmap *regmap, struct i2c_client *clnt) diff --git a/maxfg_logging.c b/maxfg_logging.c new file mode 100644 index 0000000..d4acc0a --- /dev/null +++ b/maxfg_logging.c @@ -0,0 +1,277 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Google LLC + */ + +#include <linux/err.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include "google_bms.h" +#include "max1720x_battery.h" +#include "maxfg_logging.h" + +/* learning parameters */ +#define MAX_FG_LEARNING_CONFIG_NORMAL_REGS 8 +#define MAX_FG_LEARNING_CONFIG_DEBUG_REGS 2 + +/* see maxfg_ce_relaxed() */ +static const enum max17x0x_reg_tags fg_learning_param[] = { + /* from normal regmap */ + MAXFG_TAG_fcnom, + MAXFG_TAG_dpacc, + MAXFG_TAG_dqacc, + MAXFG_TAG_fcrep, + MAXFG_TAG_repsoc, + MAXFG_TAG_msoc, + MAX17X0X_TAG_vfsoc, + MAXFG_TAG_fstat, + + /* from debug_regmap */ + MAXFG_TAG_rcomp0, + MAXFG_TAG_tempco, +}; + +/* this could be static */ +void maxfg_init_fg_learn_capture_config(struct maxfg_capture_config *config, + struct max17x0x_regmap *regmap, + struct max17x0x_regmap *debug_regmap) +{ + strscpy(config->name, "FG Learning Events", sizeof(config->name)); + config->normal.tag = &fg_learning_param[0]; + config->normal.reg_cnt = MAX_FG_LEARNING_CONFIG_NORMAL_REGS; + config->normal.regmap = regmap; + + config->debug.tag = &fg_learning_param[MAX_FG_LEARNING_CONFIG_NORMAL_REGS]; + config->debug.reg_cnt = MAX_FG_LEARNING_CONFIG_DEBUG_REGS; + config->debug.regmap = debug_regmap; + + config->data_size = ARRAY_SIZE(fg_learning_param) * sizeof(u16); +} + + +int maxfg_alloc_capture_buf(struct maxfg_capture_buf *buf, int slots) +{ + if ((slots & (slots - 1)) || !buf || !buf->config.data_size || !slots) + return -EINVAL; + + buf->slots = 0; + buf->latest_entry = NULL; + + buf->cb.buf = kzalloc(buf->config.data_size * slots, GFP_KERNEL); + if (!buf->cb.buf) + return -ENOMEM; + + buf->cb.head = 0; + buf->cb.tail = 0; + buf->slots = slots; + + mutex_init(&buf->cb_wr_lock); + mutex_init(&buf->cb_rd_lock); + + return 0; +} + +void maxfg_clear_capture_buf(struct maxfg_capture_buf *buf) +{ + if (!buf) + return; + + mutex_lock(&buf->cb_wr_lock); + mutex_lock(&buf->cb_rd_lock); + + buf->latest_entry = NULL; + buf->cb.head = 0; + buf->cb.tail = 0; + + mutex_unlock(&buf->cb_rd_lock); + mutex_unlock(&buf->cb_wr_lock); +} + +void maxfg_free_capture_buf(struct maxfg_capture_buf *buf) +{ + if (!buf) + return; + + if (buf->cb.buf && buf->slots > 0) + kfree(buf->cb.buf); + + mutex_destroy(&buf->cb_wr_lock); + mutex_destroy(&buf->cb_rd_lock); + + buf->cb.buf = NULL; + buf->slots = 0; +} + +static inline int maxfg_read_registers(struct maxfg_capture_regs *regs, u16 *buffer) +{ + int ret, idx; + + for (idx = 0; idx < regs->reg_cnt; idx++) { + ret = max17x0x_reg_read(regs->regmap, regs->tag[idx], &buffer[idx]); + if (ret < 0) { + pr_err("failed to reg_tag(%u) %d\n", regs->tag[idx], ret); + return ret; + } + } + + return 0; +} + +int maxfg_capture_registers(struct maxfg_capture_buf *buf) +{ + struct maxfg_capture_config *config = &buf->config; + const int data_size = config->data_size; + void *latest_entry; + int head, tail, ret; + u16 *reg_val; + + mutex_lock(&buf->cb_wr_lock); + + head = buf->cb.head; + tail = READ_ONCE(buf->cb.tail); + + /* if buffer is full, drop the last entry */ + if (CIRC_SPACE(head, tail, buf->slots) == 0) { + mutex_lock(&buf->cb_rd_lock); + WRITE_ONCE(buf->cb.tail, (tail + 1) & (buf->slots - 1)); + mutex_unlock(&buf->cb_rd_lock); + } + + reg_val = (u16 *)&buf->cb.buf[head * data_size]; + latest_entry = reg_val; + + ret = maxfg_read_registers(&config->normal, reg_val); + if (ret < 0) + goto exit_done; + + reg_val += config->normal.reg_cnt; + + ret = maxfg_read_registers(&config->debug, reg_val); + if (ret < 0) + goto exit_done; + + smp_wmb(); + WRITE_ONCE(buf->cb.head, (head + 1) & (buf->slots - 1)); + + buf->latest_entry = latest_entry; + +exit_done: + mutex_unlock(&buf->cb_wr_lock); + return ret; +} + +int maxfg_capture_to_cstr(struct maxfg_capture_config *config, u16 *reg_val, + char *str_buf, int buf_len) +{ + const struct max17x0x_reg *fg_reg; + int reg_idx; + int len = 0; + + for (reg_idx = 0; reg_idx < config->normal.reg_cnt && len < buf_len; reg_idx++) { + fg_reg = max17x0x_find_by_tag(config->normal.regmap, + config->normal.tag[reg_idx]); + if (!fg_reg) + return len; + + len += scnprintf(&str_buf[len], buf_len - len, "%02X:%04X ", + fg_reg->reg, reg_val[reg_idx]); + } + + reg_val += config->normal.reg_cnt; + + for (reg_idx = 0; reg_idx < config->debug.reg_cnt && len < buf_len; reg_idx++) { + fg_reg = max17x0x_find_by_tag(config->debug.regmap, + config->debug.tag[reg_idx]); + if (!fg_reg) + return len; + + len += scnprintf(&str_buf[len], buf_len - len, "%02X:%04X ", + fg_reg->reg, reg_val[reg_idx]); + } + + return len; +} + +int maxfg_show_captured_buffer(struct maxfg_capture_buf *buf, + char *str_buf, int buf_len) +{ + struct maxfg_capture_config *config = &buf->config; + const int data_size = config->data_size; + int head, tail, count, to_end, idx, rt; + u16 *reg_val; + + if (!buf) + return -EINVAL; + + mutex_lock(&buf->cb_rd_lock); + + head = READ_ONCE(buf->cb.head); + tail = buf->cb.tail; + + count = CIRC_CNT(head, tail, buf->slots); + rt = scnprintf(&str_buf[0], buf_len, "%s (%d):\n", config->name, count); + + if (count == 0) + goto maxfg_show_captured_buffer_exit; + + to_end = CIRC_CNT_TO_END(head, tail, buf->slots); + + for (idx = 0; idx < to_end && rt < buf_len; idx++) { + reg_val = (u16 *)&buf->cb.buf[(tail + idx) * data_size]; + rt += maxfg_capture_to_cstr(config, reg_val, &str_buf[rt], + buf_len - rt); + rt += scnprintf(&str_buf[rt], buf_len - rt, "\n"); + } + + count -= idx; + + for (idx = 0; idx < count && rt < buf_len; idx++) { + reg_val = (u16 *)&buf->cb.buf[idx * data_size]; + rt += maxfg_capture_to_cstr(config, reg_val, &str_buf[rt], + buf_len - rt); + rt += scnprintf(&str_buf[rt], buf_len - rt, "\n"); + } + +maxfg_show_captured_buffer_exit: + mutex_unlock(&buf->cb_rd_lock); + return rt; +} + +/* + * data in prev_val follows the order of fg_learning_param[] + * prev_val[0]: fcnom + * prev_val[1]: dpacc + * prev_val[2]: dqacc + * prev_val[7]: fstat + */ +bool maxfg_ce_relaxed(struct max17x0x_regmap *regmap, const u16 relax_mask, + const u16 *prev_val) +{ + u16 fstat, fcnom, dpacc, dqacc; + int ret; + + ret = max17x0x_reg_read(regmap, MAXFG_TAG_fstat, &fstat); + if (ret < 0) + return false; + + ret = max17x0x_reg_read(regmap, MAXFG_TAG_fcnom, &fcnom); + if (ret < 0) + return false; + + ret = max17x0x_reg_read(regmap, MAXFG_TAG_dpacc, &dpacc); + if (ret < 0) + return false; + + ret = max17x0x_reg_read(regmap, MAXFG_TAG_dqacc, &dqacc); + if (ret < 0) + return false; + + /* + * log when relaxed state changes, when fcnom, dpacc, dqacc change + * TODO: log only when dpacc, dqacc or fcnom change and simply + * count the relaxation event otherwise. + */ + return (fstat & relax_mask) != (prev_val[7] & relax_mask) || + dpacc != prev_val[1] || dqacc != prev_val[2] || + fcnom != prev_val[0]; +} diff --git a/maxfg_logging.h b/maxfg_logging.h new file mode 100644 index 0000000..ac1e63b --- /dev/null +++ b/maxfg_logging.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Google LLC + */ + +#ifndef MAXFG_LOGGING_H_ +#define MAXFG_LOGGING_H_ + +#include <linux/circ_buf.h> + +#define MAX_FG_LEARN_PARAM_MAX_HIST 32 +#define MAX_FG_CAPTURE_CONFIG_NAME_MAX 32 + +struct maxfg_capture_regs { + struct max17x0x_regmap *regmap; + const enum max17x0x_reg_tags *tag; + int reg_cnt; +}; + +/* a configuration can simply be a list of tags, a regmap and a name */ +struct maxfg_capture_config { + char name[MAX_FG_CAPTURE_CONFIG_NAME_MAX]; + struct maxfg_capture_regs normal; + struct maxfg_capture_regs debug; + int data_size; +}; + +/* only one configuration now */ +struct maxfg_capture_buf { + struct maxfg_capture_config config; + + int slots; + struct circ_buf cb; + void *latest_entry; + struct mutex cb_wr_lock; + struct mutex cb_rd_lock; +}; + +void maxfg_init_fg_learn_capture_config(struct maxfg_capture_config *config, + struct max17x0x_regmap *regmap, + struct max17x0x_regmap *debug_regmap); + +int maxfg_alloc_capture_buf(struct maxfg_capture_buf *buf, int slots); +void maxfg_clear_capture_buf(struct maxfg_capture_buf *buf); +void maxfg_free_capture_buf(struct maxfg_capture_buf *buf); + +int maxfg_capture_registers(struct maxfg_capture_buf *buf); + +int maxfg_show_captured_buffer(struct maxfg_capture_buf *buf, + char *str_buf, int buf_len); +int maxfg_capture_to_cstr(struct maxfg_capture_config *config, u16 *reg_val, + char *str_buf, int buf_len); + +bool maxfg_ce_relaxed(struct max17x0x_regmap *regmap, const u16 relax_mask, + const u16 *prev_val); + +#endif
\ No newline at end of file diff --git a/p9221_charger.c b/p9221_charger.c index 72cee14..1a208f6 100644 --- a/p9221_charger.c +++ b/p9221_charger.c @@ -6897,6 +6897,7 @@ static int p9221_charger_probe(struct i2c_client *client, } i2c_set_clientdata(client, charger); charger->dev = &client->dev; + charger->dev->init_name = "i2c-p9221"; charger->client = client; charger->pdata = pdata; charger->resume_complete = true; |