diff --git a/drivers/power/smb1360-charger-fg.c b/drivers/power/smb1360-charger-fg.c index 0326838c7123..b03513142de1 100644 --- a/drivers/power/smb1360-charger-fg.c +++ b/drivers/power/smb1360-charger-fg.c @@ -29,6 +29,7 @@ #include #include #include +#include #define _SMB1360_MASK(BITS, POS) \ ((unsigned char)(((1 << (BITS)) - 1) << (POS))) @@ -305,6 +306,22 @@ struct smb1360_otg_regulator { struct regulator_dev *rdev; }; +enum wakeup_src { + WAKEUP_SRC_FG_ACCESS = 0, + WAKEUP_SRC_JEITA_SOFT, + WAKEUP_SRC_PARALLEL, + WAKEUP_SRC_MIN_SOC, + WAKEUP_SRC_EMPTY_SOC, + WAKEUP_SRC_MAX, +}; +#define WAKEUP_SRC_MASK (~(~0 << WAKEUP_SRC_MAX)) + +struct smb1360_wakeup_source { + struct wakeup_source source; + unsigned long enabled_bitmap; + spinlock_t ws_lock; +}; + struct smb1360_chip { struct i2c_client *client; struct device *dev; @@ -318,6 +335,9 @@ struct smb1360_chip { bool pulsed_irq; struct completion fg_mem_access_granted; + /* wakeup source */ + struct smb1360_wakeup_source smb1360_ws; + /* configuration data - charger */ int fake_battery_soc; bool batt_id_disabled; @@ -444,6 +464,44 @@ static int fastchg_current[] = { 450, 600, 750, 900, 1050, 1200, 1350, 1500, }; +static void smb1360_stay_awake(struct smb1360_wakeup_source *source, + enum wakeup_src wk_src) +{ + unsigned long flags; + + spin_lock_irqsave(&source->ws_lock, flags); + + if (!__test_and_set_bit(wk_src, &source->enabled_bitmap)) { + __pm_stay_awake(&source->source); + pr_debug("enabled source %s, wakeup_src %d\n", + source->source.name, wk_src); + } + spin_unlock_irqrestore(&source->ws_lock, flags); +} + +static void smb1360_relax(struct smb1360_wakeup_source *source, + enum wakeup_src wk_src) +{ + unsigned long flags; + + spin_lock_irqsave(&source->ws_lock, flags); + if (__test_and_clear_bit(wk_src, &source->enabled_bitmap) && + !(source->enabled_bitmap & WAKEUP_SRC_MASK)) { + __pm_relax(&source->source); + pr_debug("disabled source %s\n", source->source.name); + } + spin_unlock_irqrestore(&source->ws_lock, flags); + + pr_debug("relax source %s, wakeup_src %d\n", + source->source.name, wk_src); +} + +static void smb1360_wakeup_src_init(struct smb1360_chip *chip) +{ + spin_lock_init(&chip->smb1360_ws.ws_lock); + wakeup_source_init(&chip->smb1360_ws.source, "smb1360"); +} + static int is_between(int value, int left, int right) { if (left >= right && left >= value && value >= right) @@ -762,7 +820,7 @@ static int smb1360_enable_fg_access(struct smb1360_chip *chip) * check if the access was granted before */ mutex_lock(&chip->fg_access_request_lock); - pm_stay_awake(chip->dev); + smb1360_stay_awake(&chip->smb1360_ws, WAKEUP_SRC_FG_ACCESS); rc = smb1360_read(chip, IRQ_I_REG, ®); if (rc) { pr_err("Couldn't read IRQ_I_REG, rc=%d\n", rc); @@ -803,7 +861,7 @@ static int smb1360_enable_fg_access(struct smb1360_chip *chip) } bail_i2c: - pm_relax(chip->dev); + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_FG_ACCESS); mutex_unlock(&chip->fg_access_request_lock); return rc; } @@ -1425,7 +1483,7 @@ static void smb1360_parallel_work(struct work_struct *work) } exit_work: - pm_relax(chip->dev); + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_PARALLEL); } static int smb1360_set_appropriate_usb_current(struct smb1360_chip *chip) @@ -1924,7 +1982,7 @@ static void smb1360_jeita_work_fn(struct work_struct *work) !!chip->soft_hot_rt_stat, chip->soft_jeita_supported, chip->soft_cold_thresh, chip->soft_hot_thresh); end: - pm_relax(chip->dev); + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_JEITA_SOFT); } static int hot_soft_handler(struct smb1360_chip *chip, u8 rt_stat) @@ -1938,7 +1996,8 @@ static int hot_soft_handler(struct smb1360_chip *chip, u8 rt_stat) cancel_delayed_work_sync(&chip->jeita_work); schedule_delayed_work(&chip->jeita_work, msecs_to_jiffies(JEITA_WORK_MS)); - pm_stay_awake(chip->dev); + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_JEITA_SOFT); } if (chip->parallel_charging) { @@ -1961,7 +2020,8 @@ static int cold_soft_handler(struct smb1360_chip *chip, u8 rt_stat) cancel_delayed_work_sync(&chip->jeita_work); schedule_delayed_work(&chip->jeita_work, msecs_to_jiffies(JEITA_WORK_MS)); - pm_stay_awake(chip->dev); + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_JEITA_SOFT); } if (chip->parallel_charging) { @@ -2045,7 +2105,7 @@ static int aicl_done_handler(struct smb1360_chip *chip, u8 rt_stat) if (chip->parallel_charging && aicl_done) { cancel_work_sync(&chip->parallel_work); - pm_stay_awake(chip->dev); + smb1360_stay_awake(&chip->smb1360_ws, WAKEUP_SRC_PARALLEL); schedule_work(&chip->parallel_work); } @@ -2076,7 +2136,10 @@ static int min_soc_handler(struct smb1360_chip *chip, u8 rt_stat) pr_debug("SOC dropped below min SOC, rt_stat = 0x%02x\n", rt_stat); if (chip->awake_min_soc) - rt_stat ? pm_stay_awake(chip->dev) : pm_relax(chip->dev); + rt_stat ? smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_MIN_SOC) : + smb1360_relax(&chip->smb1360_ws, + WAKEUP_SRC_MIN_SOC); return 0; } @@ -2088,11 +2151,13 @@ static int empty_soc_handler(struct smb1360_chip *chip, u8 rt_stat) if (!chip->empty_soc_disabled) { if (rt_stat) { chip->empty_soc = true; - pm_stay_awake(chip->dev); + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_EMPTY_SOC); pr_warn_ratelimited("SOC is 0\n"); } else { chip->empty_soc = false; - pm_relax(chip->dev); + smb1360_relax(&chip->smb1360_ws, + WAKEUP_SRC_EMPTY_SOC); } } @@ -4595,6 +4660,7 @@ static int smb1360_probe(struct i2c_client *client, INIT_DELAYED_WORK(&chip->delayed_init_work, smb1360_delayed_init_work_fn); init_completion(&chip->fg_mem_access_granted); + smb1360_wakeup_src_init(chip); /* probe the device to check if its actually connected */ rc = smb1360_read(chip, CFG_BATT_CHG_REG, ®);