From 2aced65bf86630e69c4d5bd5968be3bfe47db40d Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Mon, 17 Jul 2017 11:44:37 -0700 Subject: [PATCH] qcom: qnovo: restart pulse train in stall state There are a couple of cases where qnovo charging fails, 1. pulse train enable command register fails to write through, or 2. pulse engine fails to start and pulse train timer PTTIME does not start counting. In either case, qnovo charging will stop. Here is the fix, Write register twice when enabling pulse train, and restart pulse train if PTTIME does not increase. Change-Id: Ic235f8f2bc67fe577e42848ef623870c25b68256 Signed-off-by: Harry Yang Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/qpnp-qnovo.c | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index 69ea39ad5744..cf90f9041935 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo.c +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -20,6 +20,7 @@ #include #include #include +#include #define QNOVO_REVISION1 0x00 #define QNOVO_REVISION2 0x01 @@ -124,6 +125,8 @@ #define USB_READY_VOTER "USB_READY_VOTER" #define DC_READY_VOTER "DC_READY_VOTER" +#define PT_RESTART_VOTER "PT_RESTART_VOTER" + struct qnovo_dt_props { bool external_rsense; struct device_node *revid_dev_node; @@ -161,6 +164,8 @@ struct qnovo { int dc_present; struct delayed_work usb_debounce_work; struct delayed_work dc_debounce_work; + + struct delayed_work ptrain_restart_work; }; static int debug_mask; @@ -354,6 +359,11 @@ static int pt_dis_votable_cb(struct votable *votable, void *data, int disable, struct qnovo *chip = data; int rc; + if (disable) { + cancel_delayed_work_sync(&chip->ptrain_restart_work); + vote(chip->awake_votable, PT_RESTART_VOTER, false, 0); + } + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, (bool)disable ? 0 : QNOVO_PTRAIN_EN_BIT); if (rc < 0) { @@ -362,6 +372,12 @@ static int pt_dis_votable_cb(struct votable *votable, void *data, int disable, return rc; } + if (!disable) { + vote(chip->awake_votable, PT_RESTART_VOTER, true, 0); + schedule_delayed_work(&chip->ptrain_restart_work, + msecs_to_jiffies(20)); + } + return 0; } @@ -1311,6 +1327,51 @@ static void status_change_work(struct work_struct *work) qnovo_update_status(chip); } +static void ptrain_restart_work(struct work_struct *work) +{ + struct qnovo *chip = container_of(work, + struct qnovo, ptrain_restart_work.work); + u8 pt_t1, pt_t2; + int rc; + + rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t1, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n", + rc); + goto clean_up; + } + + /* pttime increments every 2 seconds */ + msleep(2100); + + rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t2, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n", + rc); + goto clean_up; + } + + if (pt_t1 != pt_t2) + goto clean_up; + + /* Toggle pt enable to restart pulse train */ + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't disable pulse train rc=%d\n", rc); + goto clean_up; + } + msleep(1000); + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, + QNOVO_PTRAIN_EN_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", rc); + goto clean_up; + } + +clean_up: + vote(chip->awake_votable, PT_RESTART_VOTER, false, 0); +} + static int qnovo_notifier_call(struct notifier_block *nb, unsigned long ev, void *v) { @@ -1564,6 +1625,7 @@ static int qnovo_probe(struct platform_device *pdev) INIT_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work); INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work); + INIT_DELAYED_WORK(&chip->ptrain_restart_work, ptrain_restart_work); rc = qnovo_hw_init(chip); if (rc < 0) {