From 5260ae84e674635d29bf1fb458e2410204cfe7f3 Mon Sep 17 00:00:00 2001 From: Ryan Lattrel Date: Wed, 22 Jan 2020 17:23:08 -0600 Subject: [PATCH] p938x_charger: Update detection algorithm Show that we are charging when VRECT_ON is triggered. This unfortunately leads to some edge cases where we will toggle the charger on and off if on the edge of the pad. Additionally clean up the remove function so that we do not race with the status interrupt in any context. We will process the removal of a charger if (1) detect IRQ goes low (2) we fail to read I2C or (3) the heartbeat function reads there is no voltage at VRECT. Change-Id: Ieec364bfa2a7bac8966dea3951d913ad7bdefee9 Signed-off-by: Ryan Lattrel Reviewed-on: https://gerrit.mot.com/1487527 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Igor Kovalenko Submit-Approved: Jira Key --- drivers/power/p938x_charger/p938x_charger.c | 92 +++++++++++++++------ 1 file changed, 68 insertions(+), 24 deletions(-) diff --git a/drivers/power/p938x_charger/p938x_charger.c b/drivers/power/p938x_charger/p938x_charger.c index fea0a2f55569..f6038fab1624 100644 --- a/drivers/power/p938x_charger/p938x_charger.c +++ b/drivers/power/p938x_charger/p938x_charger.c @@ -126,7 +126,8 @@ #define WAIT_FOR_AUTH_MS 1000 #define WAIT_FOR_RCVD_TIMEOUT_MS 1000 -#define HEARTBEAT_INTERVAL_MS 60000 +#define HEARTBEAT_INTERVAL_MS 3000 +#define HEARTBEAT_REPORT_INTERVAL 60000 #define TXMODEWORK_INTERVAL_MS 2000 #define BPP_MAX_VOUT 5000 @@ -277,6 +278,8 @@ struct p938x_charger { struct delayed_work heartbeat_work; struct delayed_work tx_mode_work; + struct delayed_work removal_work; + int heartbeat_count; u32 peek_poke_address; struct dentry *debug_root; @@ -383,26 +386,45 @@ static void p938x_pm_set_awake(struct p938x_charger *chip, int awake) } } -static int p938x_check_status(struct p938x_charger *chip); +static int p938x_get_rx_vrect(struct p938x_charger *chip); static void p938x_handle_wls_removal(struct p938x_charger *chip) { + if (!mutex_trylock(&chip->disconnect_lock)) { + cancel_delayed_work(&chip->removal_work); + schedule_delayed_work(&chip->removal_work, msecs_to_jiffies(500)); + return; + } + if(test_bit(WLS_FLAG_TX_ATTACHED, &chip->flags)) { + /* Make sure we aren't actually connect */ + if (p938x_get_rx_vrect(chip) > 0) + goto unlock; + clear_bit(WLS_FLAG_TX_ATTACHED, &chip->flags); power_supply_changed(chip->wls_psy); cancel_delayed_work(&chip->heartbeat_work); chip->stat = 0; chip->irq_stat = 0; + chip->heartbeat_count = 0; if (!test_bit(WLS_FLAG_BOOST_ENABLED, &chip->flags)) p938x_pm_set_awake(chip, 0); p938x_dbg(chip, PR_IMPORTANT, "Wireless charger is removed\n"); - - /* Just in case we aren't disconnected */ - p938x_check_status(chip); } + +unlock: + mutex_unlock(&chip->disconnect_lock); +} + +static void p938x_removal_work(struct work_struct *work) +{ + struct p938x_charger *chip = container_of(work, + struct p938x_charger, tx_mode_work.work); + + p938x_handle_wls_removal(chip); } static int p938x_read_buffer(struct p938x_charger *chip, u16 reg, @@ -666,25 +688,43 @@ static void p938x_heartbeat_work(struct work_struct *work) int vrect = 0; if (p938x_is_tx_connected(chip)) { + /* Check if we disconnected */ + vrect = p938x_get_rx_vrect(chip); + if (vrect <= 0) { + p938x_err(chip, "Detected wireless charger is not connected.\n"); + p938x_handle_wls_removal(chip); + return; + } + if (!p938x_is_ldo_on(chip)) { p938x_dbg(chip, PR_MOTO, "LDO is not on yet\n"); - cancel_delayed_work(&chip->heartbeat_work); - schedule_delayed_work(&chip->heartbeat_work, - msecs_to_jiffies(2000)); - return; + /* This is where we will trigger it after the first VRECT_ON, so + * first indication to system we have a power supply attached is VRECT_ON + * + initial delay to hb + */ + power_supply_changed(chip->wls_psy); + chip->heartbeat_count = 0; + goto schedule_hb; } vout = p938x_get_rx_vout(chip); vout_set = p938x_get_rx_vout_set(chip); - vrect = p938x_get_rx_vrect(chip); iout = p938x_get_rx_iout(chip); iout_limit = p938x_get_rx_ocl(chip); - p938x_dbg(chip, PR_IMPORTANT, - "mode=%s vout=%d vout_set=%d vrect=%d iout=%d ocl=%d\n", - chip->epp_mode ? "epp" : "bpp", - vout, vout_set, vrect, iout, iout_limit); + if (!chip->heartbeat_count) { + p938x_dbg(chip, PR_IMPORTANT, + "mode=%s vout=%d vout_set=%d vrect=%d iout=%d ocl=%d\n", + chip->epp_mode ? "epp" : "bpp", + vout, vout_set, vrect, iout, iout_limit); + } + chip->heartbeat_count++; + if (HEARTBEAT_INTERVAL_MS * chip->heartbeat_count >= + HEARTBEAT_REPORT_INTERVAL) + chip->heartbeat_count = 0; + +schedule_hb: schedule_delayed_work(&chip->heartbeat_work, msecs_to_jiffies(HEARTBEAT_INTERVAL_MS)); } @@ -1567,7 +1607,8 @@ static int p938x_check_status(struct p938x_charger *chip) sysfs_notify(&chip->dev->kobj, NULL, "rx_connected"); } - if (irq_status & status & ST_VRECT_ON) { + if ((irq_status & status & ST_VRECT_ON) || + (!test_bit(WLS_FLAG_TX_ATTACHED, &chip->flags) && (status & ST_VRECT_ON))) { if (test_bit(WLS_FLAG_TX_MODE_EN, &chip->flags)) { p938x_dbg(chip, PR_IMPORTANT, "Connected to tx pad. Disabling tx mode\n"); p938x_set_tx_mode(chip, 0); @@ -1577,13 +1618,21 @@ static int p938x_check_status(struct p938x_charger *chip) p938x_write_reg(chip, EPP_QFACTOR_REG, chip->q_factor); set_bit(WLS_FLAG_TX_ATTACHED, &chip->flags); + /* Call p938x_pm_set_awake before update supplies status. Update supplies + * status will turn it back off if we have a cable attached + */ + p938x_pm_set_awake(chip, 1); /* Update usb status incase we powered on with it connected */ p938x_update_supplies_status(chip); - p938x_pm_set_awake(chip, 1); cancel_delayed_work(&chip->heartbeat_work); + /* The power_supply_changed call is in the heartbeat. This delay is how long + * we wait for a disconnect before changing the state to charging. Without this + * we might report we are charging even if the connection is not stable enough + * to charge + */ schedule_delayed_work(&chip->heartbeat_work, - msecs_to_jiffies(2000)); + msecs_to_jiffies(1500)); p938x_dbg(chip, PR_IMPORTANT, "Wireless charger is inserted\n"); } @@ -1683,17 +1732,11 @@ static irqreturn_t p938x_irq_handler(int irq, void *dev_id) static irqreturn_t p938x_det_irq_handler(int irq, void *dev_id) { struct p938x_charger *chip = dev_id; - int tx_detected; - - mutex_lock(&chip->disconnect_lock); - - tx_detected = gpio_get_value(chip->wchg_det.gpio); + int tx_detected = gpio_get_value(chip->wchg_det.gpio); if (!tx_detected) p938x_handle_wls_removal(chip); - mutex_unlock(&chip->disconnect_lock); - return IRQ_HANDLED; } @@ -2717,6 +2760,7 @@ static int p938x_charger_probe(struct i2c_client *client, chip->debug_mask = &__debug_mask; INIT_DELAYED_WORK(&chip->heartbeat_work, p938x_heartbeat_work); INIT_DELAYED_WORK(&chip->tx_mode_work, p938x_tx_mode_work); + INIT_DELAYED_WORK(&chip->removal_work, p938x_removal_work); device_init_wakeup(chip->dev, true); chip->regmap = regmap_init_i2c(client, &p938x_regmap_config);