power: smb1360: Add multiple usages for the wakeup source

Previously, a single wakeup source is used across the driver for
multiple clients. If two or more clients held the wakeup source
and one client want to relax, it will be relaxed unintentionally
for other clients.

Manage the wakeup source status by using a global bitmap variable.
Each bit maps to one client, each client calling will update the
bitmap variable, and the wakeup source can only be relaxed if
all of the client has relaxed it intentionally.

CRs-Fixed: 846212
Change-Id: I8f93f19a8c639c8cde0b8798cc68e148d56b045e
Signed-off-by: Qiang Huang <qianghuang@codeaurora.org>
This commit is contained in:
Qiang Huang 2015-07-01 14:06:00 +08:00 committed by Gerrit - the friendly Code Review server
parent 1d41730e63
commit 629039acd8
1 changed files with 76 additions and 10 deletions

View File

@ -29,6 +29,7 @@
#include <linux/bitops.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/completion.h>
#include <linux/pm_wakeup.h>
#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, &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, &reg);