diff options
-rw-r--r-- | drivers/power/supply/qcom/qpnp-qnovo.c | 133 |
1 files changed, 87 insertions, 46 deletions
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index ada231905df9..2050785b0755 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo.c +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -272,28 +272,22 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, const char *client) { struct qnovo *chip = data; - int rc = 0; + union power_supply_propval pval = {0}; + int rc; - if (disable) { - rc = qnovo_batt_psy_update(chip, true); - if (rc < 0) - return rc; - } + if (!is_batt_available(chip)) + return -EINVAL; - rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, - disable ? 0 : QNOVO_PTRAIN_EN_BIT); + pval.intval = !disable; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, + &pval); if (rc < 0) { - dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", - disable ? "disable" : "enable", rc); - return rc; - } - - if (!disable) { - rc = qnovo_batt_psy_update(chip, false); - if (rc < 0) - return rc; + pr_err("Couldn't set prop qnovo_enable rc = %d\n", rc); + return -EINVAL; } + rc = qnovo_batt_psy_update(chip, disable); return rc; } @@ -348,7 +342,8 @@ static int qnovo_check_chg_version(struct qnovo *chip) enum { VER = 0, OK_TO_QNOVO, - ENABLE, + QNOVO_ENABLE, + PT_ENABLE, FV_REQUEST, FCC_REQUEST, PE_CTRL_REG, @@ -394,6 +389,12 @@ struct param_info { }; static struct param_info params[] = { + [PT_ENABLE] = { + .name = "PT_ENABLE", + .start_addr = QNOVO_PTRAIN_EN, + .num_regs = 1, + .units_str = "", + }, [FV_REQUEST] = { .units_str = "uV", }, @@ -648,30 +649,70 @@ static ssize_t ok_to_qnovo_show(struct class *c, struct class_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", chip->cs.ok_to_qnovo); } -static ssize_t enable_show(struct class *c, struct class_attribute *attr, +static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr, char *ubuf) { struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); - int val; + int val = get_effective_result(chip->disable_votable); - val = get_client_vote(chip->disable_votable, USER_VOTER); - val = !val; - return snprintf(ubuf, PAGE_SIZE, "%d\n", val); + return snprintf(ubuf, PAGE_SIZE, "%d\n", !val); +} + +static ssize_t qnovo_enable_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + unsigned long val; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + vote(chip->disable_votable, USER_VOTER, !val, 0); + + return count; +} + +static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = attr - qnovo_attributes; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + u16 regval; + int rc; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval = buf[1] << 8 | buf[0]; + + return snprintf(ubuf, PAGE_SIZE, "%d\n", + (int)(regval & QNOVO_PTRAIN_EN_BIT)); } -static ssize_t enable_store(struct class *c, struct class_attribute *attr, +static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr, const char *ubuf, size_t count) { struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); unsigned long val; - bool disable; + int rc = 0; + + if (get_effective_result(chip->disable_votable)) + return -EINVAL; if (kstrtoul(ubuf, 0, &val)) return -EINVAL; - disable = !val; + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, + (bool)val ? QNOVO_PTRAIN_EN_BIT : 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", + (bool)val ? "enable" : "disable", rc); + return rc; + } - vote(chip->disable_votable, USER_VOTER, disable, 0); return count; } @@ -698,6 +739,9 @@ static ssize_t val_store(struct class *c, struct class_attribute *attr, int i = attr - qnovo_attributes; unsigned long val; + if (get_effective_result(chip->disable_votable)) + return -EINVAL; + if (kstrtoul(ubuf, 0, &val)) return -EINVAL; @@ -707,6 +751,8 @@ static ssize_t val_store(struct class *c, struct class_attribute *attr, if (i == FCC_REQUEST) chip->fcc_uA_request = val; + qnovo_batt_psy_update(chip, false); + return count; } @@ -1016,8 +1062,8 @@ static ssize_t batt_prop_show(struct class *c, struct class_attribute *attr, static struct class_attribute qnovo_attributes[] = { [VER] = __ATTR_RO(version), [OK_TO_QNOVO] = __ATTR_RO(ok_to_qnovo), - [ENABLE] = __ATTR(enable, 0644, - enable_show, enable_store), + [QNOVO_ENABLE] = __ATTR_RW(qnovo_enable), + [PT_ENABLE] = __ATTR_RW(pt_enable), [FV_REQUEST] = __ATTR(fv_uV_request, 0644, val_show, val_store), [FCC_REQUEST] = __ATTR(fcc_uA_request, 0644, @@ -1050,7 +1096,7 @@ static struct class_attribute qnovo_attributes[] = { time_show, NULL), [PREST2] = __ATTR(PREST2_mS, 0644, time_show, time_store), - [PPULS2] = __ATTR(PPULS2_mS, 0644, + [PPULS2] = __ATTR(PPULS2_uC, 0644, coulomb_show, coulomb_store), [NREST2] = __ATTR(NREST2_mS, 0644, time_show, time_store), @@ -1135,8 +1181,7 @@ static void get_chg_status(struct qnovo *chip, const struct chg_props *cp, { cs->ok_to_qnovo = false; - if (cp->charging && - (cp->usb_online || cp->dc_online)) + if (cp->charging && (cp->usb_online || cp->dc_online)) cs->ok_to_qnovo = true; } @@ -1152,17 +1197,10 @@ static void status_change_work(struct work_struct *work) get_chg_status(chip, &cp, &cs); if (cs.ok_to_qnovo ^ chip->cs.ok_to_qnovo) { - /* - * when it is not okay to Qnovo charge, disable both voters, - * so that when it becomes okay to Qnovo charge the user voter - * has to specifically enable its vote to being Qnovo charging - */ - if (!cs.ok_to_qnovo) { - vote(chip->disable_votable, OK_TO_QNOVO_VOTER, 1, 0); - vote(chip->disable_votable, USER_VOTER, 1, 0); - } else { - vote(chip->disable_votable, OK_TO_QNOVO_VOTER, 0, 0); - } + vote(chip->disable_votable, OK_TO_QNOVO_VOTER, + !cs.ok_to_qnovo, 0); + if (!cs.ok_to_qnovo) + vote(chip->disable_votable, USER_VOTER, true, 0); notify_uevent = true; } @@ -1192,8 +1230,6 @@ static irqreturn_t handle_ptrain_done(int irq, void *data) { struct qnovo *chip = data; - /* disable user voter here */ - vote(chip->disable_votable, USER_VOTER, 0, 0); kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); return IRQ_HANDLED; } @@ -1206,7 +1242,7 @@ static int qnovo_hw_init(struct qnovo *chip) u8 vadc_offset, vadc_gain; u8 val; - vote(chip->disable_votable, USER_VOTER, 1, 0); + vote(chip->disable_votable, USER_VOTER, true, 0); val = 0; rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); @@ -1318,6 +1354,9 @@ static int qnovo_request_interrupts(struct qnovo *chip) irq_ptrain_done, rc); return rc; } + + enable_irq_wake(irq_ptrain_done); + return rc; } @@ -1399,6 +1438,8 @@ static int qnovo_probe(struct platform_device *pdev) goto unreg_notifier; } + device_init_wakeup(chip->dev, true); + return rc; unreg_notifier: |