From a3946ad93eec7b35b18078d4cb2801c20e9e46c5 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Wed, 7 Sep 2016 16:17:47 -0700 Subject: qpnp-fg-gen3: add algorithm flags debugfs file The fuel gauge has several algorithm flags which are useful for debugging. Add a debugfs file called alg_flags to expose them. Change-Id: Ibeeea88e2e0745e98e8bfdfa3e086263d82e7bac Signed-off-by: Nicholas Troast --- drivers/power/qcom-charger/fg-core.h | 23 +++++- drivers/power/qcom-charger/fg-util.c | 112 ++++++++++++++++++++++++------ drivers/power/qcom-charger/qpnp-fg-gen3.c | 80 +++++++++++++++++++-- 3 files changed, 188 insertions(+), 27 deletions(-) diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h index a609d8fcd400..4feaaa0e0c4e 100644 --- a/drivers/power/qcom-charger/fg-core.h +++ b/drivers/power/qcom-charger/fg-core.h @@ -114,6 +114,7 @@ enum fg_sram_param_id { FG_SRAM_VOLTAGE_PRED, FG_SRAM_OCV, FG_SRAM_RSLOW, + FG_SRAM_ALG_FLAGS, /* Entries below here are configurable during initialization */ FG_SRAM_CUTOFF_VOLT, FG_SRAM_EMPTY_VOLT, @@ -143,6 +144,23 @@ struct fg_sram_param { int val); }; +enum fg_alg_flag_id { + ALG_FLAG_SOC_LT_OTG_MIN = 0, + ALG_FLAG_SOC_LT_RECHARGE, + ALG_FLAG_IBATT_LT_ITERM, + ALG_FLAG_IBATT_GT_HPM, + ALG_FLAG_IBATT_GT_UPM, + ALG_FLAG_VBATT_LT_RECHARGE, + ALG_FLAG_VBATT_GT_VFLOAT, + ALG_FLAG_MAX, +}; + +struct fg_alg_flag { + char *name; + u8 bit; + bool invalid; +}; + /* DT parameters for FG device */ struct fg_dt_props { int cutoff_volt_mv; @@ -179,7 +197,7 @@ struct fg_chip { struct device *dev; struct pmic_revid_data *pmic_rev_id; struct regmap *regmap; - struct dentry *dentry; + struct dentry *dfs_root; struct power_supply *fg_psy; struct power_supply *batt_psy; struct iio_channel *batt_id_chan; @@ -205,6 +223,7 @@ struct fg_chip { struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; + struct fg_alg_flag *alg_flags; }; /* Debugfs data structures are below */ @@ -249,7 +268,7 @@ extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_ima_init(struct fg_chip *chip); -extern int fg_sram_debugfs_create(struct fg_chip *chip); +extern int fg_debugfs_create(struct fg_chip *chip); extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len); extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos); extern s64 fg_float_decode(u16 val); diff --git a/drivers/power/qcom-charger/fg-util.c b/drivers/power/qcom-charger/fg-util.c index 0d52fb5ba9b8..bf5a446452a4 100644 --- a/drivers/power/qcom-charger/fg-util.c +++ b/drivers/power/qcom-charger/fg-util.c @@ -611,27 +611,23 @@ static const struct file_operations fg_sram_dfs_reg_fops = { * fg_debugfs_create: adds new fg_sram debugfs entry * @return zero on success */ -int fg_sram_debugfs_create(struct fg_chip *chip) +static int fg_sram_debugfs_create(struct fg_chip *chip) { - struct dentry *root; + struct dentry *dfs_sram; struct dentry *file; mode_t dfs_mode = S_IRUSR | S_IWUSR; pr_debug("Creating FG_SRAM debugfs file-system\n"); - root = debugfs_create_dir("fg_sram", NULL); - if (IS_ERR_OR_NULL(root)) { - pr_err("Error creating top level directory err:%ld", - (long)root); - if (PTR_ERR(root) == -ENODEV) - pr_err("debugfs is not enabled in the kernel"); - return -ENODEV; + dfs_sram = debugfs_create_dir("sram", chip->dfs_root); + if (!dfs_sram) { + pr_err("error creating fg sram dfs rc=%ld\n", + (long)dfs_sram); + return -ENOMEM; } - if (!root) - return -ENOENT; - dbgfs_data.help_msg.size = strlen(dbgfs_data.help_msg.data); - file = debugfs_create_blob("help", S_IRUGO, root, &dbgfs_data.help_msg); + file = debugfs_create_blob("help", S_IRUGO, dfs_sram, + &dbgfs_data.help_msg); if (!file) { pr_err("error creating help entry\n"); goto err_remove_fs; @@ -639,30 +635,106 @@ int fg_sram_debugfs_create(struct fg_chip *chip) dbgfs_data.chip = chip; - file = debugfs_create_u32("count", dfs_mode, root, &(dbgfs_data.cnt)); + file = debugfs_create_u32("count", dfs_mode, dfs_sram, + &(dbgfs_data.cnt)); if (!file) { pr_err("error creating 'count' entry\n"); goto err_remove_fs; } - file = debugfs_create_x32("address", dfs_mode, - root, &(dbgfs_data.addr)); + file = debugfs_create_x32("address", dfs_mode, dfs_sram, + &(dbgfs_data.addr)); if (!file) { pr_err("error creating 'address' entry\n"); goto err_remove_fs; } - file = debugfs_create_file("data", dfs_mode, root, &dbgfs_data, - &fg_sram_dfs_reg_fops); + file = debugfs_create_file("data", dfs_mode, dfs_sram, &dbgfs_data, + &fg_sram_dfs_reg_fops); if (!file) { pr_err("error creating 'data' entry\n"); goto err_remove_fs; } - chip->dentry = root; return 0; err_remove_fs: - debugfs_remove_recursive(root); + debugfs_remove_recursive(dfs_sram); + return -ENOMEM; +} + +static int fg_alg_flags_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t fg_alg_flags_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct fg_chip *chip = file->private_data; + char buf[512]; + u8 alg_flags = 0; + int rc, i, len; + + rc = fg_sram_read(chip, chip->sp[FG_SRAM_ALG_FLAGS].addr_word, + chip->sp[FG_SRAM_ALG_FLAGS].addr_byte, &alg_flags, 1, + FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("failed to read algorithm flags rc=%d\n", rc); + return -EFAULT; + } + + len = 0; + for (i = 0; i < ALG_FLAG_MAX; ++i) { + if (len > ARRAY_SIZE(buf) - 1) + return -EFAULT; + if (chip->alg_flags[i].invalid) + continue; + + len += snprintf(buf + len, sizeof(buf) - sizeof(*buf) * len, + "%s = %d\n", chip->alg_flags[i].name, + (bool)(alg_flags & chip->alg_flags[i].bit)); + } + + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static const struct file_operations fg_alg_flags_fops = { + .open = fg_alg_flags_open, + .read = fg_alg_flags_read, +}; + +int fg_debugfs_create(struct fg_chip *chip) +{ + int rc; + + pr_debug("Creating debugfs file-system\n"); + chip->dfs_root = debugfs_create_dir("fg", NULL); + if (IS_ERR_OR_NULL(chip->dfs_root)) { + if (PTR_ERR(chip->dfs_root) == -ENODEV) + pr_err("debugfs is not enabled in the kernel\n"); + else + pr_err("error creating fg dfs root rc=%ld\n", + (long)chip->dfs_root); + return -ENODEV; + } + + rc = fg_sram_debugfs_create(chip); + if (rc < 0) { + pr_err("failed to create sram dfs rc=%d\n", rc); + goto err_remove_fs; + } + + if (!debugfs_create_file("alg_flags", S_IRUSR, chip->dfs_root, chip, + &fg_alg_flags_fops)) { + pr_err("failed to create alg_flags file\n"); + goto err_remove_fs; + } + + return 0; + +err_remove_fs: + debugfs_remove_recursive(chip->dfs_root); return -ENOMEM; } diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c index dda94bb3f932..5d59d0940991 100644 --- a/drivers/power/qcom-charger/qpnp-fg-gen3.c +++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c @@ -73,6 +73,8 @@ #define LAST_BATT_SOC_OFFSET 0 #define LAST_MONOTONIC_SOC_WORD 119 #define LAST_MONOTONIC_SOC_OFFSET 2 +#define ALG_FLAGS_WORD 120 +#define ALG_FLAGS_OFFSET 1 /* v2 SRAM address and offset in ascending order */ #define DELTA_SOC_THR_v2_WORD 13 @@ -119,6 +121,8 @@ static struct fg_sram_param pmicobalt_v1_sram_params[] = { fg_decode_value_16b), PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 244141, 1000, 0, NULL, fg_decode_value_16b), + PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL, + fg_decode_default), /* Entries below here are configurable during initialization */ PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000, 244141, 0, fg_encode_voltage, NULL), @@ -155,6 +159,8 @@ static struct fg_sram_param pmicobalt_v2_sram_params[] = { fg_decode_value_16b), PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 244141, 1000, 0, NULL, fg_decode_value_16b), + PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL, + fg_decode_default), /* Entries below here are configurable during initialization */ PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000, 244141, 0, fg_encode_voltage, NULL), @@ -183,6 +189,67 @@ static struct fg_sram_param pmicobalt_v2_sram_params[] = { ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), }; +static struct fg_alg_flag pmicobalt_v1_alg_flags[] = { + [ALG_FLAG_SOC_LT_OTG_MIN] = { + .name = "SOC_LT_OTG_MIN", + .bit = BIT(0), + }, + [ALG_FLAG_SOC_LT_RECHARGE] = { + .name = "SOC_LT_RECHARGE", + .bit = BIT(1), + }, + [ALG_FLAG_IBATT_LT_ITERM] = { + .name = "IBATT_LT_ITERM", + .bit = BIT(2), + }, + [ALG_FLAG_IBATT_GT_HPM] = { + .name = "IBATT_GT_HPM", + .bit = BIT(3), + }, + [ALG_FLAG_IBATT_GT_UPM] = { + .name = "IBATT_GT_UPM", + .bit = BIT(4), + }, + [ALG_FLAG_VBATT_LT_RECHARGE] = { + .name = "VBATT_LT_RECHARGE", + .bit = BIT(5), + }, + [ALG_FLAG_VBATT_GT_VFLOAT] = { + .invalid = true, + }, +}; + +static struct fg_alg_flag pmicobalt_v2_alg_flags[] = { + [ALG_FLAG_SOC_LT_OTG_MIN] = { + .name = "SOC_LT_OTG_MIN", + .bit = BIT(0), + }, + [ALG_FLAG_SOC_LT_RECHARGE] = { + .name = "SOC_LT_RECHARGE", + .bit = BIT(1), + }, + [ALG_FLAG_IBATT_LT_ITERM] = { + .name = "IBATT_LT_ITERM", + .bit = BIT(2), + }, + [ALG_FLAG_IBATT_GT_HPM] = { + .name = "IBATT_GT_HPM", + .bit = BIT(4), + }, + [ALG_FLAG_IBATT_GT_UPM] = { + .name = "IBATT_GT_UPM", + .bit = BIT(5), + }, + [ALG_FLAG_VBATT_LT_RECHARGE] = { + .name = "VBATT_LT_RECHARGE", + .bit = BIT(6), + }, + [ALG_FLAG_VBATT_GT_VFLOAT] = { + .name = "VBATT_GT_VFLOAT", + .bit = BIT(7), + }, +}; + static int fg_gen3_debug_mask; module_param_named( debug_mask, fg_gen3_debug_mask, int, S_IRUSR | S_IWUSR @@ -1318,12 +1385,15 @@ static int fg_parse_dt(struct fg_chip *chip) switch (chip->pmic_rev_id->pmic_subtype) { case PMICOBALT_SUBTYPE: - if (chip->pmic_rev_id->rev4 < PMICOBALT_V2P0_REV4) + if (chip->pmic_rev_id->rev4 < PMICOBALT_V2P0_REV4) { chip->sp = pmicobalt_v1_sram_params; - else if (chip->pmic_rev_id->rev4 == PMICOBALT_V2P0_REV4) + chip->alg_flags = pmicobalt_v1_alg_flags; + } else if (chip->pmic_rev_id->rev4 == PMICOBALT_V2P0_REV4) { chip->sp = pmicobalt_v2_sram_params; - else + chip->alg_flags = pmicobalt_v2_alg_flags; + } else { return -EINVAL; + } break; default: return -EINVAL; @@ -1465,7 +1535,7 @@ static int fg_parse_dt(struct fg_chip *chip) static void fg_cleanup(struct fg_chip *chip) { power_supply_unreg_notifier(&chip->nb); - debugfs_remove_recursive(chip->dentry); + debugfs_remove_recursive(chip->dfs_root); if (chip->awake_votable) destroy_votable(chip->awake_votable); @@ -1562,7 +1632,7 @@ static int fg_gen3_probe(struct platform_device *pdev) if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); - rc = fg_sram_debugfs_create(chip); + rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", rc); -- cgit v1.2.3 From 3603cc87ba28802d0f8e12245cdce4f296b5b16b Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Tue, 20 Sep 2016 15:33:20 -0700 Subject: qpnp-smb2: add missing battery psy properties for healthd healthd expects battery voltage, current, temperature, and technology from the battery power supply. Add them. Change-Id: I85f589030903ead938af2712875eb5daa81710d9 Signed-off-by: Nicholas Troast --- drivers/power/qcom-charger/qpnp-smb2.c | 21 ++++++++++++++++-- drivers/power/qcom-charger/smb-lib.c | 39 ++++++++++++++++++++++++++++++++++ drivers/power/qcom-charger/smb-lib.h | 6 ++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 32b374cbb67f..d19e7827ed83 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -596,14 +596,17 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TECHNOLOGY, }; static int smb2_batt_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - struct smb2 *chip = power_supply_get_drvdata(psy); - struct smb_charger *chg = &chip->chg; + struct smb_charger *chg = power_supply_get_drvdata(psy); int rc = 0; switch (psp) { @@ -637,14 +640,28 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: rc = smblib_get_prop_input_current_limited(chg, val); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + rc = smblib_get_prop_batt_voltage_now(chg, val); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + rc = smblib_get_prop_batt_current_now(chg, val); + break; + case POWER_SUPPLY_PROP_TEMP: + rc = smblib_get_prop_batt_temp(chg, val); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; } + if (rc < 0) { pr_debug("Couldn't get prop %d rc = %d\n", psp, rc); return -ENODATA; } + return 0; } diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 21b330127369..ed24e12e313d 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -1003,6 +1003,45 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, return 0; } +int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, val); + return rc; +} + +int smblib_get_prop_batt_current_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, val); + return rc; +} + +int smblib_get_prop_batt_temp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_TEMP, val); + return rc; +} + /*********************** * BATTERY PSY SETTERS * ***********************/ diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index aeb1eb2c454f..289fb1706e97 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -222,6 +222,12 @@ int smblib_get_prop_system_temp_level(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_batt_current_now(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_batt_temp(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); -- cgit v1.2.3