pmic-voter: improve pmic-voter api implementation

Currently the pmic-voter api assumes that the clients are represented
as unique integers. Using strings instead of integers adds flexibility.
- It enables the votable to be shared across multiple drivers without
  having a common client enum
- Debug prints become more useful

While at it
- remove the use of num_clients in the apis. All of them default to
  NUM_CLIENTS.
- Create a list of all the votables, this allows for searching for a
  specific votable.
- Error if a votable is already created with the same name earlier.
- Add debug prints about current clients and effective results
- Remove passing in last_client and last_client_id in the callback. These
  parameters go unused in all the usecases.
- Since clients are assigned sequentially and that they cannot
  unregister from a votable (clients can only disable their votes, but
  they cannot remove themselves), a null string in the client string
  array means there are no more clients. Use this to speed up result
  calculation by stopping at the id with a null string.
- Refactor the vote() implementation. Currently the SET_ANY case flows
  differently than MIN or MAX, make them uniform.
- Create an api to call the callback without casting new votes.

CRs-Fixed: 1018090
Change-Id: I8e2bc3366ec12e8485e4be86ee56ba5e4d113c3c
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
This commit is contained in:
Abhijeet Dharmapurikar 2016-05-17 20:09:16 -07:00 committed by Kyle Yan
parent 31bcecd1a2
commit 74d9ef758e
5 changed files with 407 additions and 274 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015 The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
#include <linux/debugfs.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/bitops.h>
@ -20,15 +21,21 @@
#define NUM_MAX_CLIENTS 8
static DEFINE_SPINLOCK(votable_list_slock);
static LIST_HEAD(votable_list);
static struct dentry *debug_root;
struct client_vote {
int state;
bool enabled;
int value;
};
struct votable {
const char *name;
struct list_head list;
struct client_vote votes[NUM_MAX_CLIENTS];
struct device *dev;
const char *name;
int num_clients;
int type;
int effective_client_id;
@ -37,53 +44,84 @@ struct votable {
struct mutex vote_lock;
int (*callback)(struct device *dev,
int effective_result,
int effective_client,
int last_result,
int last_client);
const char *effective_client);
char *client_strs[NUM_MAX_CLIENTS];
struct dentry *ent;
};
static int vote_set_any(struct votable *votable)
static void vote_set_any(struct votable *votable, int client_id,
int *eff_res, int *eff_id)
{
int i;
for (i = 0; i < votable->num_clients; i++)
if (votable->votes[i].state == 1)
return 1;
return 0;
for (i = 0; i < votable->num_clients && votable->client_strs[i]; i++)
*eff_res |= votable->votes[i].enabled;
*eff_id = client_id;
}
static int vote_min(struct votable *votable)
static void vote_min(struct votable *votable, int client_id,
int *eff_res, int *eff_id)
{
int i;
*eff_res = INT_MAX;
*eff_id = -EINVAL;
for (i = 0; i < votable->num_clients && votable->client_strs[i]; i++) {
if (votable->votes[i].enabled
&& *eff_res > votable->votes[i].value) {
*eff_res = votable->votes[i].value;
*eff_id = i;
}
}
}
static void vote_max(struct votable *votable, int client_id,
int *eff_res, int *eff_id)
{
int i;
*eff_res = INT_MIN;
*eff_id = -EINVAL;
for (i = 0; i < votable->num_clients && votable->client_strs[i]; i++) {
if (votable->votes[i].enabled &&
*eff_res < votable->votes[i].value) {
*eff_res = votable->votes[i].value;
*eff_id = i;
}
}
}
static int get_client_id(struct votable *votable, const char *client_str)
{
int min_vote = INT_MAX;
int client_index = -EINVAL;
int i;
for (i = 0; i < votable->num_clients; i++) {
if (votable->votes[i].state == 1 &&
min_vote > votable->votes[i].value) {
min_vote = votable->votes[i].value;
client_index = i;
}
if (votable->client_strs[i]
&& (strcmp(votable->client_strs[i], client_str) == 0))
return i;
}
return client_index;
/* new client */
for (i = 0; i < votable->num_clients; i++) {
if (!votable->client_strs[i]) {
votable->client_strs[i]
= devm_kstrdup(votable->dev,
client_str, GFP_KERNEL);
if (!votable->client_strs[i])
return -ENOMEM;
return i;
}
}
return -EINVAL;
}
static int vote_max(struct votable *votable)
static char *get_client_str(struct votable *votable, int client_id)
{
int max_vote = INT_MIN;
int client_index = -EINVAL;
int i;
if (client_id == -EINVAL)
return NULL;
for (i = 0; i < votable->num_clients; i++) {
if (votable->votes[i].state == 1 &&
max_vote < votable->votes[i].value) {
max_vote = votable->votes[i].value;
client_index = i;
}
}
return client_index;
return votable->client_strs[client_id];
}
void lock_votable(struct votable *votable)
@ -96,30 +134,26 @@ void unlock_votable(struct votable *votable)
mutex_unlock(&votable->vote_lock);
}
int get_client_vote(struct votable *votable, int client_id)
int get_client_vote_locked(struct votable *votable, const char *client_str)
{
int value;
int client_id = get_client_id(votable, client_str);
lock_votable(votable);
value = get_client_vote_locked(votable, client_id);
unlock_votable(votable);
return value;
}
if (client_id < 0)
return votable->default_result;
int get_client_vote_locked(struct votable *votable, int client_id)
{
if (votable->votes[client_id].state < 0)
if ((votable->type != VOTE_SET_ANY)
&& !votable->votes[client_id].enabled)
return votable->default_result;
return votable->votes[client_id].value;
}
int get_effective_result(struct votable *votable)
int get_client_vote(struct votable *votable, const char *client_str)
{
int value;
lock_votable(votable);
value = get_effective_result_locked(votable);
value = get_client_vote_locked(votable, client_str);
unlock_votable(votable);
return value;
}
@ -132,60 +166,73 @@ int get_effective_result_locked(struct votable *votable)
return votable->effective_result;
}
int get_effective_client_id(struct votable *votable)
int get_effective_result(struct votable *votable)
{
int id;
int value;
lock_votable(votable);
id = get_effective_client_id_locked(votable);
value = get_effective_result_locked(votable);
unlock_votable(votable);
return id;
return value;
}
int get_effective_client_id_locked(struct votable *votable)
const char *get_effective_client_locked(struct votable *votable)
{
return votable->effective_client_id;
return get_client_str(votable, votable->effective_client_id);
}
int vote(struct votable *votable, int client_id, bool state, int val)
const char *get_effective_client(struct votable *votable)
{
int effective_id = - EINVAL;
const char *client_str;
lock_votable(votable);
client_str = get_effective_client_locked(votable);
unlock_votable(votable);
return client_str;
}
int vote(struct votable *votable, const char *client_str, bool enabled, int val)
{
int effective_id = -EINVAL;
int effective_result;
int client_id;
int rc = 0;
lock_votable(votable);
if (votable->votes[client_id].state == state &&
votable->votes[client_id].value == val) {
pr_debug("%s: votes unchanged; skipping\n", votable->name);
client_id = get_client_id(votable, client_str);
if (client_id < 0) {
rc = client_id;
goto out;
}
votable->votes[client_id].state = state;
if (votable->votes[client_id].enabled == enabled &&
votable->votes[client_id].value == val) {
pr_debug("%s: %s,%d same vote %s of %d\n",
votable->name,
client_str, client_id,
enabled ? "on" : "off",
val);
goto out;
}
votable->votes[client_id].enabled = enabled;
votable->votes[client_id].value = val;
pr_debug("%s: %d voting for %d - %s\n",
votable->name,
client_id, val, state ? "on" : "off");
pr_debug("%s: %s,%d voting %s of %d\n",
votable->name,
client_str, client_id, enabled ? "on" : "off", val);
switch (votable->type) {
case VOTE_MIN:
effective_id = vote_min(votable);
vote_min(votable, client_id, &effective_result, &effective_id);
break;
case VOTE_MAX:
effective_id = vote_max(votable);
vote_max(votable, client_id, &effective_result, &effective_id);
break;
case VOTE_SET_ANY:
votable->votes[client_id].value = state;
effective_result = vote_set_any(votable);
if (effective_result != votable->effective_result) {
votable->effective_client_id = client_id;
votable->effective_result = effective_result;
if (votable->callback)
rc = votable->callback(votable->dev,
effective_result, client_id,
state, client_id);
}
goto out;
vote_set_any(votable, client_id,
&effective_result, &effective_id);
break;
}
/*
@ -197,16 +244,16 @@ int vote(struct votable *votable, int client_id, bool state, int val)
goto out;
}
effective_result = votable->votes[effective_id].value;
if (effective_result != votable->effective_result) {
votable->effective_client_id = effective_id;
votable->effective_result = effective_result;
pr_debug("%s: effective vote is now %d voted by %d\n",
votable->name, effective_result, effective_id);
pr_debug("%s: effective vote is now %d voted by %s,%d\n",
votable->name, effective_result,
get_client_str(votable, effective_id),
effective_id);
if (votable->callback)
rc = votable->callback(votable->dev, effective_result,
effective_id, val, client_id);
get_client_str(votable, effective_id));
}
out:
@ -214,37 +261,134 @@ out:
return rc;
}
int rerun_election(struct votable *votable)
{
int rc = 0;
lock_votable(votable);
if (votable->callback)
rc = votable->callback(votable->dev,
votable->effective_result,
get_client_str(votable, votable->effective_client_id));
unlock_votable(votable);
return rc;
}
struct votable *find_votable(const char *name)
{
unsigned long flags;
struct votable *v;
bool found = false;
spin_lock_irqsave(&votable_list_slock, flags);
if (list_empty(&votable_list))
goto out;
list_for_each_entry(v, &votable_list, list) {
if (strcmp(v->name, name) == 0) {
found = true;
break;
}
}
out:
spin_unlock_irqrestore(&votable_list_slock, flags);
if (found)
return v;
else
return NULL;
}
static int show_votable_clients(struct seq_file *m, void *data)
{
struct votable *votable = m->private;
int i;
char *type_str = "Unkonwn";
lock_votable(votable);
seq_puts(m, "Clients:\n");
for (i = 0; i < votable->num_clients; i++) {
if (votable->client_strs[i]) {
seq_printf(m, "%-15s:\t\ten=%d\t\tv=%d\n",
votable->client_strs[i],
votable->votes[i].enabled,
votable->votes[i].value);
}
}
switch (votable->type) {
case VOTE_MIN:
type_str = "Min";
break;
case VOTE_MAX:
type_str = "Max";
break;
case VOTE_SET_ANY:
type_str = "Set_any";
break;
}
seq_printf(m, "Type: %s\n", type_str);
seq_puts(m, "Effective:\n");
seq_printf(m, "%-15s:\t\tv=%d\n",
get_effective_client_locked(votable),
get_effective_result_locked(votable));
unlock_votable(votable);
return 0;
}
static int votable_debugfs_open(struct inode *inode, struct file *file)
{
struct votable *votable = inode->i_private;
return single_open(file, show_votable_clients, votable);
}
static const struct file_operations votable_debugfs_ops = {
.owner = THIS_MODULE,
.open = votable_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
struct votable *create_votable(struct device *dev, const char *name,
int votable_type,
int num_clients,
int default_result,
int (*callback)(struct device *dev,
int effective_result,
int effective_client,
int last_result,
int last_client)
int effective_result,
const char *effective_client)
)
{
int i;
struct votable *votable;
unsigned long flags;
votable = find_votable(name);
if (votable)
return ERR_PTR(-EEXIST);
if (debug_root == NULL) {
debug_root = debugfs_create_dir("pmic-votable", NULL);
if (!debug_root) {
dev_err(dev, "Couldn't create debug dir\n");
return ERR_PTR(-ENOMEM);
}
}
if (votable_type >= NUM_VOTABLE_TYPES) {
dev_err(dev, "Invalid votable_type specified for voter\n");
return ERR_PTR(-EINVAL);
}
if (num_clients > NUM_MAX_CLIENTS) {
dev_err(dev, "Invalid num_clients specified for voter\n");
return ERR_PTR(-EINVAL);
}
votable = devm_kzalloc(dev, sizeof(struct votable), GFP_KERNEL);
if (!votable)
return ERR_PTR(-ENOMEM);
votable->dev = dev;
votable->name = name;
votable->num_clients = num_clients;
votable->num_clients = NUM_MAX_CLIENTS;
votable->callback = callback;
votable->type = votable_type;
votable->default_result = default_result;
@ -257,8 +401,30 @@ struct votable *create_votable(struct device *dev, const char *name,
votable->effective_result = -EINVAL;
votable->effective_client_id = -EINVAL;
for (i = 0; i < votable->num_clients; i++)
votable->votes[i].state = -EINVAL;
spin_lock_irqsave(&votable_list_slock, flags);
list_add(&votable->list, &votable_list);
spin_unlock_irqrestore(&votable_list_slock, flags);
votable->ent = debugfs_create_file(name, S_IFREG | S_IRUGO,
debug_root, votable,
&votable_debugfs_ops);
if (!votable->ent) {
dev_err(dev, "Couldn't create %s debug file\n", name);
devm_kfree(dev, votable);
return ERR_PTR(-EEXIST);
}
return votable;
}
void destroy_votable(struct device *dev, struct votable *votable)
{
unsigned long flags;
/* only disengage from list, mem will be freed with dev release */
spin_lock_irqsave(&votable_list_slock, flags);
list_del(&votable->list);
spin_unlock_irqrestore(&votable_list_slock, flags);
debugfs_remove(votable->ent);
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015 The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -24,23 +24,23 @@ enum votable_type {
NUM_VOTABLE_TYPES,
};
int get_client_vote(struct votable *votable, int client_id);
int get_client_vote_locked(struct votable *votable, int client_id);
int get_client_vote(struct votable *votable, const char *client_str);
int get_client_vote_locked(struct votable *votable, const char *client_str);
int get_effective_result(struct votable *votable);
int get_effective_result_locked(struct votable *votable);
int get_effective_client_id(struct votable *votable);
int get_effective_client_id_locked(struct votable *votable);
int vote(struct votable *votable, int client_id, bool state, int val);
const char *get_effective_client(struct votable *votable);
const char *get_effective_client_locked(struct votable *votable);
int vote(struct votable *votable, const char *client_str, bool state, int val);
int rerun_election(struct votable *votable);
struct votable *find_votable(const char *name);
struct votable *create_votable(struct device *dev, const char *name,
int votable_type, int num_clients,
int default_result,
int votable_type, int default_result,
int (*callback)(struct device *dev,
int effective_result,
int effective_client,
int last_result,
int last_client)
const char *effective_client)
);
void destroy_votable(struct device *dev, struct votable *votable);
void lock_votable(struct votable *votable);
void unlock_votable(struct votable *votable);
void unlock_votable(struct votable *votable);
#endif /* __PMIC_VOTER_H */

View file

@ -338,96 +338,79 @@ enum wake_reason {
PM_DETECT_HVDCP = BIT(4),
};
enum fcc_voters {
ESR_PULSE_FCC_VOTER,
BATT_TYPE_FCC_VOTER,
RESTRICTED_CHG_FCC_VOTER,
NUM_FCC_VOTER,
};
/* fcc_voters */
#define ESR_PULSE_FCC_VOTER "ESR_PULSE_FCC_VOTER"
#define BATT_TYPE_FCC_VOTER "BATT_TYPE_FCC_VOTER"
#define RESTRICTED_CHG_FCC_VOTER "RESTRICTED_CHG_FCC_VOTER"
enum icl_voters {
PSY_ICL_VOTER,
THERMAL_ICL_VOTER,
HVDCP_ICL_VOTER,
USER_ICL_VOTER,
WEAK_CHARGER_ICL_VOTER,
SW_AICL_ICL_VOTER,
CHG_SUSPEND_WORKAROUND_ICL_VOTER,
NUM_ICL_VOTER,
};
/* ICL VOTERS */
#define PSY_ICL_VOTER "PSY_ICL_VOTER"
#define THERMAL_ICL_VOTER "THERMAL_ICL_VOTER"
#define HVDCP_ICL_VOTER "HVDCP_ICL_VOTER"
#define USER_ICL_VOTER "USER_ICL_VOTER"
#define WEAK_CHARGER_ICL_VOTER "WEAK_CHARGER_ICL_VOTER"
#define SW_AICL_ICL_VOTER "SW_AICL_ICL_VOTER"
#define CHG_SUSPEND_WORKAROUND_ICL_VOTER "CHG_SUSPEND_WORKAROUND_ICL_VOTER"
enum enable_voters {
/* userspace has suspended charging altogether */
USER_EN_VOTER,
/*
* this specific path has been suspended through the power supply
* framework
*/
POWER_SUPPLY_EN_VOTER,
/*
* the usb driver has suspended this path by setting a current limit
* of < 2MA
*/
USB_EN_VOTER,
/*
* when a wireless charger comes online,
* the dc path is suspended for a second
*/
WIRELESS_EN_VOTER,
/*
* the thermal daemon can suspend a charge path when the system
* temperature levels rise
*/
THERMAL_EN_VOTER,
/*
* an external OTG supply is being used, suspend charge path so the
* charger does not accidentally try to charge from the external supply.
*/
OTG_EN_VOTER,
/*
* the charger is very weak, do not draw any current from it
*/
WEAK_CHARGER_EN_VOTER,
/*
* fake battery voter, if battery id-resistance around 7.5 Kohm
*/
FAKE_BATTERY_EN_VOTER,
NUM_EN_VOTERS,
};
/* USB SUSPEND VOTERS */
/* userspace has suspended charging altogether */
#define USER_EN_VOTER "USER_EN_VOTER"
/*
* this specific path has been suspended through the power supply
* framework
*/
#define POWER_SUPPLY_EN_VOTER "POWER_SUPPLY_EN_VOTER"
/*
* the usb driver has suspended this path by setting a current limit
* of < 2MA
*/
#define USB_EN_VOTER "USB_EN_VOTER"
/*
* the thermal daemon can suspend a charge path when the system
* temperature levels rise
*/
#define THERMAL_EN_VOTER "THERMAL_EN_VOTER"
/*
* an external OTG supply is being used, suspend charge path so the
* charger does not accidentally try to charge from the external supply.
*/
#define OTG_EN_VOTER "OTG_EN_VOTER"
/*
* the charger is very weak, do not draw any current from it
*/
#define WEAK_CHARGER_EN_VOTER "WEAK_CHARGER_EN_VOTER"
/*
* fake battery voter, if battery id-resistance around 7.5 Kohm
*/
#define FAKE_BATTERY_EN_VOTER "FAKE_BATTERY_EN_VOTER"
enum battchg_enable_voters {
/* battchg_enable_voters */
/* userspace has disabled battery charging */
BATTCHG_USER_EN_VOTER,
#define BATTCHG_USER_EN_VOTER "BATTCHG_USER_EN_VOTER"
/* battery charging disabled while loading battery profiles */
BATTCHG_UNKNOWN_BATTERY_EN_VOTER,
NUM_BATTCHG_EN_VOTERS,
};
#define BATTCHG_UNKNOWN_BATTERY_EN_VOTER "BATTCHG_UNKNOWN_BATTERY_EN_VOTER"
enum hw_aicl_rerun_enable_indirect_voters {
/* enabled via device tree */
DEFAULT_CONFIG_HW_AICL_VOTER,
/* Varb workaround voter */
VARB_WORKAROUND_VOTER,
/* SHUTDOWN workaround voter */
SHUTDOWN_WORKAROUND_VOTER,
NUM_HW_AICL_RERUN_ENABLE_INDIRECT_VOTERS,
};
/* hw_aicl_rerun_enable_indirect_voters */
/* enabled via device tree */
#define DEFAULT_CONFIG_HW_AICL_VOTER "DEFAULT_CONFIG_HW_AICL_VOTER"
/* Varb workaround voter */
#define VARB_WORKAROUND_VOTER "VARB_WORKAROUND_VOTER"
/* SHUTDOWN workaround voter */
#define SHUTDOWN_WORKAROUND_VOTER "SHUTDOWN_WORKAROUND_VOTER"
enum hw_aicl_rerun_disable_voters {
/* the results from enabling clients */
HW_AICL_RERUN_ENABLE_INDIRECT_VOTER,
/* Weak charger voter */
WEAK_CHARGER_HW_AICL_VOTER,
NUM_HW_AICL_DISABLE_VOTERS,
};
/* hw_aicl_rerun_disable_voters */
/* the results from enabling clients */
#define HW_AICL_RERUN_ENABLE_INDIRECT_VOTER \
"HW_AICL_RERUN_ENABLE_INDIRECT_VOTER"
/* Weak charger voter */
#define WEAK_CHARGER_HW_AICL_VOTER "WEAK_CHARGER_HW_AICL_VOTER"
enum aicl_short_deglitch_voters {
/* Varb workaround voter */
VARB_WORKAROUND_SHORT_DEGLITCH_VOTER,
/* QC 2.0 */
HVDCP_SHORT_DEGLITCH_VOTER,
NUM_HW_SHORT_DEGLITCH_VOTERS,
};
/* aicl_short_deglitch_voters */
/* Varb workaround voter */
#define VARB_WORKAROUND_SHORT_DEGLITCH_VOTER \
"VARB_WRKARND_SHORT_DEGLITCH_VOTER"
/* QC 2.0 */
#define HVDCP_SHORT_DEGLITCH_VOTER "HVDCP_SHORT_DEGLITCH_VOTER"
static const unsigned int smbchg_extcon_cable[] = {
EXTCON_USB,
@ -2136,7 +2119,8 @@ static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip,
ktime_t kt_since_last_disable;
u8 reg;
int fcc_ma = get_effective_result_locked(chip->fcc_votable);
int fcc_voter_id = get_effective_client_id_locked(chip->fcc_votable);
const char *fcc_voter
= get_effective_client_locked(chip->fcc_votable);
int usb_icl_ma = get_effective_result_locked(chip->usb_icl_votable);
if (!parallel_psy || !smbchg_parallel_en
@ -2216,11 +2200,13 @@ static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip,
return false;
}
if (!fcc_voter)
return false;
/*
* Suspend the parallel charger if the charging current is < 1800 mA
* and is not because of an ESR pulse.
*/
if (fcc_voter_id != ESR_PULSE_FCC_VOTER
if ((strcmp(fcc_voter, ESR_PULSE_FCC_VOTER) == 0)
&& fcc_ma < PARALLEL_CHG_THRESHOLD_CURRENT) {
pr_smb(PR_STATUS, "FCC %d lower than %d\n",
fcc_ma,
@ -2325,8 +2311,7 @@ static void smbchg_parallel_usb_check_ok(struct smbchg_chip *chip)
}
static int charging_suspend_vote_cb(struct device *dev, int suspend,
int client, int last_suspend,
int last_client)
const char *client)
{
int rc;
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -2342,8 +2327,7 @@ static int charging_suspend_vote_cb(struct device *dev, int suspend,
}
static int usb_suspend_vote_cb(struct device *dev, int suspend,
int client, int last_suspend,
int last_client)
const char *client)
{
int rc;
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -2352,17 +2336,17 @@ static int usb_suspend_vote_cb(struct device *dev, int suspend,
if (rc < 0)
return rc;
if (client == THERMAL_EN_VOTER || client == POWER_SUPPLY_EN_VOTER ||
client == USER_EN_VOTER ||
client == FAKE_BATTERY_EN_VOTER)
if ((strcmp(client, THERMAL_EN_VOTER) == 0)
|| (strcmp(client, POWER_SUPPLY_EN_VOTER) == 0)
|| (strcmp(client, USER_EN_VOTER) == 0)
|| (strcmp(client, FAKE_BATTERY_EN_VOTER) == 0))
smbchg_parallel_usb_check_ok(chip);
return rc;
}
static int dc_suspend_vote_cb(struct device *dev, int suspend,
int client, int last_suspend,
int last_client)
const char *client)
{
int rc;
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -2379,9 +2363,7 @@ static int dc_suspend_vote_cb(struct device *dev, int suspend,
static int set_fastchg_current_vote_cb(struct device *dev,
int fcc_ma,
int client,
int last_fcc_ma,
int last_client)
const char *client)
{
struct smbchg_chip *chip = dev_get_drvdata(dev);
int rc;
@ -2667,9 +2649,7 @@ DEFINE_SIMPLE_ATTRIBUTE(force_dcin_icl_ops, NULL,
*/
static int set_dc_current_limit_vote_cb(struct device *dev,
int icl_ma,
int client,
int last_icl_ma,
int last_client)
const char *client)
{
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -2682,17 +2662,19 @@ static int set_dc_current_limit_vote_cb(struct device *dev,
*/
static int set_usb_current_limit_vote_cb(struct device *dev,
int icl_ma,
int client,
int last_icl_ma,
int last_client)
const char *client)
{
struct smbchg_chip *chip = dev_get_drvdata(dev);
int rc, aicl_ma, effective_id;
int rc, aicl_ma;
const char *effective_id;
effective_id = get_effective_client_id_locked(chip->usb_icl_votable);
effective_id = get_effective_client_locked(chip->usb_icl_votable);
if (!effective_id)
return 0;
/* disable parallel charging if HVDCP is voting for 300mA */
if (effective_id == HVDCP_ICL_VOTER)
if (strcmp(effective_id, HVDCP_ICL_VOTER) == 0)
smbchg_parallel_usb_disable(chip);
if (chip->parallel.current_max_ma == 0) {
@ -2704,7 +2686,7 @@ static int set_usb_current_limit_vote_cb(struct device *dev,
}
/* skip the aicl rerun if hvdcp icl voter is active */
if (effective_id == HVDCP_ICL_VOTER)
if (strcmp(effective_id, HVDCP_ICL_VOTER) == 0)
return 0;
aicl_ma = smbchg_get_aicl_level_ma(chip);
@ -3268,8 +3250,7 @@ static void smbchg_soc_changed(struct smbchg_chip *chip)
static int smbchg_hw_aicl_rerun_enable_indirect_cb(struct device *dev,
int enable,
int client, int last_enable,
int last_client)
const char *client)
{
int rc = 0;
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -3289,8 +3270,7 @@ static int smbchg_hw_aicl_rerun_enable_indirect_cb(struct device *dev,
}
static int smbchg_hw_aicl_rerun_disable_cb(struct device *dev, int disable,
int client, int last_disable,
int last_client)
const char *client)
{
int rc = 0;
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -3305,8 +3285,7 @@ static int smbchg_hw_aicl_rerun_disable_cb(struct device *dev, int disable,
}
static int smbchg_aicl_deglitch_config_cb(struct device *dev, int shorter,
int client, int last_result,
int last_client)
const char *client)
{
int rc = 0;
struct smbchg_chip *chip = dev_get_drvdata(dev);
@ -7943,64 +7922,64 @@ static int smbchg_probe(struct platform_device *pdev)
}
chip->fcc_votable = create_votable(&pdev->dev,
"SMBCHG: fcc",
VOTE_MIN, NUM_FCC_VOTER, 2000,
"BATT_FCC",
VOTE_MIN, 2000,
set_fastchg_current_vote_cb);
if (IS_ERR(chip->fcc_votable))
return PTR_ERR(chip->fcc_votable);
chip->usb_icl_votable = create_votable(&pdev->dev,
"SMBCHG: usb_icl",
VOTE_MIN, NUM_ICL_VOTER, 3000,
"USB_ICL",
VOTE_MIN, 3000,
set_usb_current_limit_vote_cb);
if (IS_ERR(chip->usb_icl_votable))
return PTR_ERR(chip->usb_icl_votable);
chip->dc_icl_votable = create_votable(&pdev->dev,
"SMBCHG: dcl_icl",
VOTE_MIN, NUM_ICL_VOTER, 3000,
"DCIN_ICL",
VOTE_MIN, 3000,
set_dc_current_limit_vote_cb);
if (IS_ERR(chip->dc_icl_votable))
return PTR_ERR(chip->dc_icl_votable);
chip->usb_suspend_votable = create_votable(&pdev->dev,
"SMBCHG: usb_suspend",
VOTE_SET_ANY, NUM_EN_VOTERS, 0,
"USB_SUSPEND",
VOTE_SET_ANY, 0,
usb_suspend_vote_cb);
if (IS_ERR(chip->usb_suspend_votable))
return PTR_ERR(chip->usb_suspend_votable);
chip->dc_suspend_votable = create_votable(&pdev->dev,
"SMBCHG: dc_suspend",
VOTE_SET_ANY, NUM_EN_VOTERS, 0,
"DC_SUSPEND",
VOTE_SET_ANY, 0,
dc_suspend_vote_cb);
if (IS_ERR(chip->dc_suspend_votable))
return PTR_ERR(chip->dc_suspend_votable);
chip->battchg_suspend_votable = create_votable(&pdev->dev,
"SMBCHG: battchg_suspend",
VOTE_SET_ANY, NUM_BATTCHG_EN_VOTERS, 0,
"BATTCHG_SUSPEND",
VOTE_SET_ANY, 0,
charging_suspend_vote_cb);
if (IS_ERR(chip->battchg_suspend_votable))
return PTR_ERR(chip->battchg_suspend_votable);
chip->hw_aicl_rerun_disable_votable = create_votable(&pdev->dev,
"SMBCHG: hwaicl_disable",
VOTE_SET_ANY, NUM_HW_AICL_DISABLE_VOTERS, 0,
"HWAICL_DISABLE",
VOTE_SET_ANY, 0,
smbchg_hw_aicl_rerun_disable_cb);
if (IS_ERR(chip->hw_aicl_rerun_disable_votable))
return PTR_ERR(chip->hw_aicl_rerun_disable_votable);
chip->hw_aicl_rerun_enable_indirect_votable = create_votable(&pdev->dev,
"SMBCHG: hwaicl_enable_indirect",
VOTE_SET_ANY, NUM_HW_AICL_RERUN_ENABLE_INDIRECT_VOTERS,
0, smbchg_hw_aicl_rerun_enable_indirect_cb);
"HWAICL_ENABLE_INDIRECT",
VOTE_SET_ANY, 0,
smbchg_hw_aicl_rerun_enable_indirect_cb);
if (IS_ERR(chip->hw_aicl_rerun_enable_indirect_votable))
return PTR_ERR(chip->hw_aicl_rerun_enable_indirect_votable);
chip->aicl_deglitch_short_votable = create_votable(&pdev->dev,
"SMBCHG: hwaicl_short_deglitch",
VOTE_SET_ANY, NUM_HW_SHORT_DEGLITCH_VOTERS, 0,
"HWAICL_SHORT_DEGLITCH",
VOTE_SET_ANY, 0,
smbchg_aicl_deglitch_config_cb);
if (IS_ERR(chip->aicl_deglitch_short_votable))
return PTR_ERR(chip->aicl_deglitch_short_votable);
@ -8217,7 +8196,7 @@ static int smbchg_remove(struct platform_device *pdev)
static void smbchg_shutdown(struct platform_device *pdev)
{
struct smbchg_chip *chip = dev_get_drvdata(&pdev->dev);
int i, rc;
int rc;
if (!(chip->wa_flags & SMBCHG_RESTART_WA))
return;
@ -8256,8 +8235,10 @@ static void smbchg_shutdown(struct platform_device *pdev)
disable_irq(chip->wdog_timeout_irq);
/* remove all votes for short deglitch */
for (i = 0; i < NUM_HW_SHORT_DEGLITCH_VOTERS; i++)
vote(chip->aicl_deglitch_short_votable, i, false, 0);
vote(chip->aicl_deglitch_short_votable,
VARB_WORKAROUND_SHORT_DEGLITCH_VOTER, false, 0);
vote(chip->aicl_deglitch_short_votable,
HVDCP_SHORT_DEGLITCH_VOTER, false, 0);
/* vote to ensure AICL rerun is enabled */
rc = vote(chip->hw_aicl_rerun_enable_indirect_votable,

View file

@ -299,24 +299,24 @@ static int smblib_detach_usb(struct smb_charger *chg)
* VOTABLE CALLBACKS *
*********************/
int smblib_usb_suspend_vote_callback(struct device *dev,
int suspend, int client, int last_suspend, int last_client)
static int smblib_usb_suspend_vote_callback(struct device *dev,
int suspend, const char *client)
{
struct smb_charger *chg = dev_get_drvdata(dev);
return smblib_set_usb_suspend(chg, suspend);
}
int smblib_dc_suspend_vote_callback(struct device *dev,
int suspend, int client, int last_suspend, int last_client)
static int smblib_dc_suspend_vote_callback(struct device *dev,
int suspend, const char *client)
{
struct smb_charger *chg = dev_get_drvdata(dev);
return smblib_set_dc_suspend(chg, suspend);
}
int smblib_fcc_vote_callback(struct device *dev,
int fcc_ua, int client, int last_fcc_ua, int last_client)
static int smblib_fcc_vote_callback(struct device *dev,
int fcc_ua, const char *client)
{
struct smb_charger *chg = dev_get_drvdata(dev);
int rc = 0;
@ -325,8 +325,8 @@ int smblib_fcc_vote_callback(struct device *dev,
return rc;
}
int smblib_fv_vote_callback(struct device *dev,
int fv_uv, int client, int last_fv_uv, int last_client)
static int smblib_fv_vote_callback(struct device *dev,
int fv_uv, const char *client)
{
struct smb_charger *chg = dev_get_drvdata(dev);
int rc = 0;
@ -337,8 +337,8 @@ int smblib_fv_vote_callback(struct device *dev,
#define USBIN_25MA 25000
#define USBIN_100MA 100000
int smblib_usb_icl_vote_callback(struct device *dev,
int icl_ua, int client, int last_icl_ua, int last_client)
static int smblib_usb_icl_vote_callback(struct device *dev,
int icl_ua, const char *client)
{
struct smb_charger *chg = dev_get_drvdata(dev);
int rc = 0;
@ -372,8 +372,8 @@ suspend:
return rc;
}
int smblib_dc_icl_vote_callback(struct device *dev,
int icl_ua, int client, int last_icl_ua, int last_client)
static int smblib_dc_icl_vote_callback(struct device *dev,
int icl_ua, const char *client)
{
struct smb_charger *chg = dev_get_drvdata(dev);
int rc = 0;
@ -1295,7 +1295,7 @@ int smblib_init(struct smb_charger *chg)
chg->usb_suspend_votable = create_votable(chg->dev,
"INPUT_SUSPEND", VOTE_SET_ANY,
NUM_VOTERS, 0,
0,
smblib_usb_suspend_vote_callback);
if (IS_ERR(chg->usb_suspend_votable)) {
rc = PTR_ERR(chg->usb_suspend_votable);
@ -1304,7 +1304,7 @@ int smblib_init(struct smb_charger *chg)
chg->dc_suspend_votable = create_votable(chg->dev,
"DC_SUSPEND", VOTE_SET_ANY,
NUM_VOTERS, 0,
0,
smblib_dc_suspend_vote_callback);
if (IS_ERR(chg->dc_suspend_votable)) {
rc = PTR_ERR(chg->dc_suspend_votable);
@ -1313,7 +1313,7 @@ int smblib_init(struct smb_charger *chg)
chg->fcc_votable = create_votable(chg->dev,
"FCC", VOTE_MAX,
NUM_VOTERS, SMB_DEFAULT_FCC_UA,
SMB_DEFAULT_FCC_UA,
smblib_fcc_vote_callback);
if (IS_ERR(chg->fcc_votable)) {
rc = PTR_ERR(chg->fcc_votable);
@ -1322,7 +1322,7 @@ int smblib_init(struct smb_charger *chg)
chg->fv_votable = create_votable(chg->dev,
"FV", VOTE_MAX,
NUM_VOTERS, SMB_DEFAULT_FV_UV,
SMB_DEFAULT_FV_UV,
smblib_fv_vote_callback);
if (IS_ERR(chg->fv_votable)) {
rc = PTR_ERR(chg->fv_votable);
@ -1331,7 +1331,7 @@ int smblib_init(struct smb_charger *chg)
chg->usb_icl_votable = create_votable(chg->dev,
"USB_ICL", VOTE_MIN,
NUM_VOTERS, SMB_DEFAULT_ICL_UA,
SMB_DEFAULT_ICL_UA,
smblib_usb_icl_vote_callback);
if (IS_ERR(chg->usb_icl_votable)) {
rc = PTR_ERR(chg->usb_icl_votable);
@ -1340,7 +1340,7 @@ int smblib_init(struct smb_charger *chg)
chg->dc_icl_votable = create_votable(chg->dev,
"DC_ICL", VOTE_MIN,
NUM_VOTERS, SMB_DEFAULT_ICL_UA,
SMB_DEFAULT_ICL_UA,
smblib_dc_icl_vote_callback);
if (IS_ERR(chg->dc_icl_votable)) {
rc = PTR_ERR(chg->dc_icl_votable);
@ -1349,7 +1349,7 @@ int smblib_init(struct smb_charger *chg)
chg->pd_allowed_votable = create_votable(chg->dev,
"PD_ALLOWED", VOTE_SET_ANY,
NUM_VOTERS, 0, NULL);
0, NULL);
if (IS_ERR(chg->pd_allowed_votable)) {
rc = PTR_ERR(chg->pd_allowed_votable);
return rc;

View file

@ -23,12 +23,9 @@ enum print_reason {
PR_MISC = BIT(2),
};
enum smb_voters {
DEFAULT_VOTER = 0,
USER_VOTER,
PD_VOTER,
NUM_VOTERS,
};
#define DEFAULT_VOTER "DEFAULT_VOTER"
#define USER_VOTER "USER_VOTER"
#define PD_VOTER "PD_VOTER"
struct smb_regulator {
struct regulator_dev *rdev;
@ -101,17 +98,6 @@ int smblib_write(struct smb_charger *chg, u16 addr, u8 val);
int smblib_enable_charging(struct smb_charger *chg, bool enable);
int smblib_usb_suspend_vote_callback(struct device *dev,
int disable, int client, int last_disable, int last_client);
int smblib_dc_suspend_vote_callback(struct device *dev,
int disable, int client, int last_disable, int last_client);
int smblib_fcc_vote_callback(struct device *dev,
int fcc_ua, int client, int last_fcc_ua, int last_client);
int smblib_usb_icl_vote_callback(struct device *dev,
int icl_ua, int client, int last_icl_ua, int last_client);
int smblib_dc_icl_vote_callback(struct device *dev,
int icl_ua, int client, int last_icl_ua, int last_client);
int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev);