mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 14:19:09 -04:00
add paired battery info notification
Add paired battery notification to limit the battery load to system power and charging speed. Change-Id: Ia416fe0b69bb6535e2874f518dcbb8d534dc3039 Signed-off-by: yanyh2 <yanyh2@motorola.com> Reviewed-on: https://gerrit.mot.com/2186534 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Jianqi Yang <yangj@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
8975cef12d
commit
f6da73c6b9
2 changed files with 349 additions and 5 deletions
|
|
@ -72,11 +72,23 @@ enum SGM4154x_VINDPM_OS {
|
|||
VINDPM_OS_10500mV,
|
||||
};
|
||||
|
||||
enum {
|
||||
PAIRED_LOAD_OFF,
|
||||
PAIRED_LOAD_LOW,
|
||||
PAIRED_LOAD_HIGH,
|
||||
};
|
||||
|
||||
static enum power_supply_usb_type sgm4154x_usb_type[] = {
|
||||
POWER_SUPPLY_USB_TYPE_UNKNOWN,
|
||||
POWER_SUPPLY_USB_TYPE_SDP,
|
||||
POWER_SUPPLY_USB_TYPE_DCP,
|
||||
POWER_SUPPLY_USB_TYPE_CDP,
|
||||
POWER_SUPPLY_USB_TYPE_SDP, /* Standard Downstream Port */
|
||||
POWER_SUPPLY_USB_TYPE_DCP, /* Dedicated Charging Port */
|
||||
POWER_SUPPLY_USB_TYPE_CDP, /* Charging Downstream Port */
|
||||
POWER_SUPPLY_USB_TYPE_ACA, /* Accessory Charger Adapters */
|
||||
POWER_SUPPLY_USB_TYPE_C, /* Type C Port */
|
||||
POWER_SUPPLY_USB_TYPE_PD, /* Power Delivery Port */
|
||||
POWER_SUPPLY_USB_TYPE_PD_DRP, /* PD Dual Role Port */
|
||||
POWER_SUPPLY_USB_TYPE_PD_PPS, /* PD Programmable Power Supply */
|
||||
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */
|
||||
};
|
||||
|
||||
static int sgm4154x_usb_notifier(struct notifier_block *nb, unsigned long val,
|
||||
|
|
@ -1470,6 +1482,7 @@ static int sgm4154x_parse_dt(struct sgm4154x_device *sgm)
|
|||
int ret;
|
||||
//u32 val = 0;
|
||||
int irq_gpio = 0, irqn = 0;
|
||||
enum of_gpio_flags flags;
|
||||
const char *usb_psy_name = NULL;
|
||||
|
||||
#if 0
|
||||
|
|
@ -1482,6 +1495,40 @@ static int sgm4154x_parse_dt(struct sgm4154x_device *sgm)
|
|||
sgm->watchdog_timer < SGM4154x_WATCHDOG_DIS)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
sgm->high_load_en_gpio = of_get_named_gpio_flags(sgm->dev->of_node,
|
||||
"mmi,high-load-en-gpio", 0, &flags);
|
||||
if (gpio_is_valid(sgm->high_load_en_gpio)) {
|
||||
ret = gpio_request(sgm->high_load_en_gpio,
|
||||
"high-load-en-gpio");
|
||||
if (ret) {
|
||||
dev_err(sgm->dev, "%s: %d gpio request failed\n",
|
||||
__func__, sgm->high_load_en_gpio);
|
||||
sgm->high_load_en_gpio = -EINVAL;
|
||||
} else {
|
||||
sgm->high_load_active_low = !!(flags & OF_GPIO_ACTIVE_LOW);
|
||||
/* Disable batt high load switch by default */
|
||||
gpio_direction_output(sgm->high_load_en_gpio,
|
||||
sgm->high_load_active_low);
|
||||
}
|
||||
}
|
||||
|
||||
sgm->low_load_en_gpio = of_get_named_gpio_flags(sgm->dev->of_node,
|
||||
"mmi,low-load-en-gpio", 0, &flags);
|
||||
if (gpio_is_valid(sgm->low_load_en_gpio)) {
|
||||
ret = gpio_request(sgm->low_load_en_gpio,
|
||||
"low-load-en-gpio");
|
||||
if (ret) {
|
||||
dev_err(sgm->dev, "%s: %d gpio request failed\n",
|
||||
__func__, sgm->low_load_en_gpio);
|
||||
sgm->low_load_en_gpio = -EINVAL;
|
||||
} else {
|
||||
sgm->low_load_active_low = !!(flags & OF_GPIO_ACTIVE_LOW);
|
||||
/* Disable batt low load switch by default */
|
||||
gpio_direction_output(sgm->low_load_en_gpio,
|
||||
sgm->low_load_active_low);
|
||||
}
|
||||
}
|
||||
|
||||
ret = device_property_read_string(sgm->dev,
|
||||
"mmi,ext-usb-psy-name",
|
||||
&usb_psy_name);
|
||||
|
|
@ -1933,7 +1980,7 @@ static int sgm4154x_charger_get_batt_info(void *data, struct mmi_battery_info *b
|
|||
chg->batt_info.batt_mv = val.intval / 1000;
|
||||
rc = power_supply_get_property(chg->fg_psy, POWER_SUPPLY_PROP_CURRENT_NOW, &val);
|
||||
if (!rc)
|
||||
chg->batt_info.batt_ma = val.intval / 1000;
|
||||
chg->batt_info.batt_ma = val.intval / 1000 * chg->ichg_polority;
|
||||
rc = power_supply_get_property(chg->fg_psy, POWER_SUPPLY_PROP_CAPACITY, &val);
|
||||
if (!rc)
|
||||
chg->batt_info.batt_soc = val.intval;
|
||||
|
|
@ -1960,6 +2007,7 @@ static int sgm4154x_charger_get_batt_info(void *data, struct mmi_battery_info *b
|
|||
|
||||
static int sgm4154x_charger_get_chg_info(void *data, struct mmi_charger_info *chg_info)
|
||||
{
|
||||
int ret;
|
||||
struct sgm_mmi_charger *chg = data;
|
||||
struct sgm4154x_state state = chg->sgm->state;
|
||||
|
||||
|
|
@ -1969,6 +2017,18 @@ static int sgm4154x_charger_get_chg_info(void *data, struct mmi_charger_info *ch
|
|||
chg->chg_info.chrg_present = state.online;
|
||||
chg->chg_info.vbus_present = state.vbus_gd;
|
||||
|
||||
if (state.ibus_limit > 0) {
|
||||
ret = sgm4154x_get_input_curr_lim(chg->sgm);
|
||||
if (ret < 0) {
|
||||
chg->chg_info.chrg_pmax_mw = 0;
|
||||
} else {
|
||||
chg->chg_info.chrg_pmax_mw = (ret / 1000) *
|
||||
(state.vbus_adc / 1000) / 1000;
|
||||
}
|
||||
} else {
|
||||
chg->chg_info.chrg_pmax_mw = 0;
|
||||
}
|
||||
|
||||
memcpy(chg_info, &chg->chg_info, sizeof(struct mmi_charger_info));
|
||||
|
||||
return 0;
|
||||
|
|
@ -1991,7 +2051,7 @@ static int sgm4154x_charger_config_charge(void *data, struct mmi_charger_cfg *co
|
|||
}
|
||||
}
|
||||
if (config->target_fcc != chg->chg_cfg.target_fcc) {
|
||||
value = config->target_fcc * 1000;
|
||||
value = min(config->target_fcc * 1000, chg->paired_ichg);
|
||||
rc = sgm4154x_set_ichrg_curr(chg->sgm, value);
|
||||
if (!rc) {
|
||||
cfg_changed = true;
|
||||
|
|
@ -2154,9 +2214,99 @@ static void sgm4154x_charger_set_constraint(void *data,
|
|||
}
|
||||
}
|
||||
|
||||
static void sgm4154x_paired_battery_notify(void *data,
|
||||
struct mmi_battery_info *batt_info)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
u32 value;
|
||||
int delta_vbat;
|
||||
int delta_soc;
|
||||
bool high_load_en;
|
||||
bool low_load_en;
|
||||
struct sgm_mmi_charger *chg = data;
|
||||
int paired_ichg = chg->paired_ichg;
|
||||
int paired_load = chg->paired_load;
|
||||
static bool initialized = false;
|
||||
|
||||
if (!batt_info)
|
||||
return;
|
||||
|
||||
delta_vbat = chg->batt_info.batt_mv - batt_info->batt_mv;
|
||||
delta_soc = chg->batt_info.batt_soc - batt_info->batt_soc;
|
||||
|
||||
if (chg->paired_ichg_table && chg->paired_ichg_table_len) {
|
||||
paired_ichg = 0;
|
||||
for (i = 0; i < chg->paired_ichg_table_len; i++) {
|
||||
if (delta_soc <= chg->paired_ichg_table[i * 2]) {
|
||||
paired_ichg = chg->paired_ichg_table[i * 2 + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
paired_ichg *= 1000;
|
||||
}
|
||||
if (paired_ichg != chg->paired_ichg) {
|
||||
value = min(chg->chg_cfg.target_fcc * 1000, chg->paired_ichg);
|
||||
rc = sgm4154x_set_ichrg_curr(chg->sgm, value);
|
||||
if (!rc)
|
||||
chg->paired_ichg = paired_ichg;
|
||||
}
|
||||
|
||||
if (!initialized &&
|
||||
chg->paired_load_thres && chg->paired_load_thres_len) {
|
||||
initialized = true;
|
||||
paired_load = PAIRED_LOAD_HIGH;
|
||||
for (i = 0; i < chg->paired_load_thres_len; i++) {
|
||||
if (delta_vbat > chg->paired_load_thres[i]) {
|
||||
paired_load = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
WARN_ON(paired_load == PAIRED_LOAD_OFF);
|
||||
}
|
||||
|
||||
if (initialized &&
|
||||
paired_ichg > 0 &&
|
||||
chg->paired_load != PAIRED_LOAD_HIGH) {
|
||||
chg->paired_load = PAIRED_LOAD_HIGH;
|
||||
}
|
||||
|
||||
if (paired_load != chg->paired_load) {
|
||||
chg->paired_load = paired_load;
|
||||
switch (paired_load) {
|
||||
case PAIRED_LOAD_OFF:
|
||||
high_load_en = false;
|
||||
low_load_en = false;
|
||||
break;
|
||||
case PAIRED_LOAD_LOW:
|
||||
high_load_en = false;
|
||||
low_load_en = true;
|
||||
break;
|
||||
case PAIRED_LOAD_HIGH:
|
||||
default:
|
||||
high_load_en = true;
|
||||
low_load_en = false;
|
||||
}
|
||||
if (gpio_is_valid(chg->sgm->high_load_en_gpio)) {
|
||||
gpio_set_value(chg->sgm->high_load_en_gpio,
|
||||
high_load_en ^ chg->sgm->high_load_active_low);
|
||||
}
|
||||
if (gpio_is_valid(chg->sgm->low_load_en_gpio)) {
|
||||
gpio_set_value(chg->sgm->low_load_en_gpio,
|
||||
low_load_en ^ chg->sgm->low_load_active_low);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
pr_info("delta_vbat: %dmV, delta_soc: %d, paired_ichg: %duA, paired_load: %d\n",
|
||||
delta_vbat, delta_soc, paired_ichg, paired_load);
|
||||
}
|
||||
|
||||
static int sgm4154x_mmi_charger_init(struct sgm_mmi_charger *chg)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
int byte_len;
|
||||
const char *df_sn = NULL;
|
||||
struct mmi_charger_driver *driver;
|
||||
|
||||
|
|
@ -2190,6 +2340,68 @@ static int sgm4154x_mmi_charger_init(struct sgm_mmi_charger *chg)
|
|||
strcpy(chg->batt_info.batt_sn, df_sn);
|
||||
chg->chg_cfg.charging_disable = chg->sgm->init_data.charger_disabled;
|
||||
|
||||
if (of_property_read_bool(chg->sgm->dev->of_node, "mmi,ichg-invert-polority"))
|
||||
chg->ichg_polority = -1;
|
||||
else
|
||||
chg->ichg_polority = 1;
|
||||
chg->paired_ichg = chg->sgm->init_data.max_ichg;
|
||||
chg->paired_load = PAIRED_LOAD_OFF;
|
||||
if (!chg->paired_ichg_table &&
|
||||
of_find_property(chg->sgm->dev->of_node, "mmi,paired-ichg-table", &byte_len)) {
|
||||
if ((byte_len / sizeof(u32)) % 2) {
|
||||
pr_err("DT error wrong paired-ichg-table\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chg->paired_ichg_table = (int *)devm_kzalloc(chg->sgm->dev, byte_len, GFP_KERNEL);
|
||||
if (chg->paired_ichg_table == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chg->paired_ichg_table_len = byte_len / sizeof(u32) / 2;
|
||||
rc = of_property_read_u32_array(chg->sgm->dev->of_node,
|
||||
"mmi,paired-ichg-table",
|
||||
(u32 *)chg->paired_ichg_table,
|
||||
byte_len / sizeof(u32));
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read paired-ichg-table rc = %d\n", rc);
|
||||
devm_kfree(chg->sgm->dev, chg->paired_ichg_table);
|
||||
chg->paired_ichg_table = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_info("paired-ichg-table: len: %d\n", chg->paired_ichg_table_len);
|
||||
for (i = 0; i < chg->paired_ichg_table_len; i++) {
|
||||
pr_info("paired-ichg-table[%d]: delta_soc %d, fcc %dmA\n", i,
|
||||
chg->paired_ichg_table[i * 2],
|
||||
chg->paired_ichg_table[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!chg->paired_load_thres &&
|
||||
of_find_property(chg->sgm->dev->of_node, "mmi,paired-load-thres", &byte_len)) {
|
||||
chg->paired_load_thres = (int *)devm_kzalloc(chg->sgm->dev, byte_len, GFP_KERNEL);
|
||||
if (chg->paired_load_thres == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chg->paired_load_thres_len = byte_len / sizeof(u32);
|
||||
rc = of_property_read_u32_array(chg->sgm->dev->of_node,
|
||||
"mmi,paired-load-thres",
|
||||
(u32 *)chg->paired_load_thres,
|
||||
byte_len / sizeof(u32));
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read paired-load-thres rc = %d\n", rc);
|
||||
devm_kfree(chg->sgm->dev, chg->paired_load_thres);
|
||||
chg->paired_load_thres = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_info("paired-load-thres: len: %d\n", chg->paired_load_thres_len);
|
||||
for (i = 0; i < chg->paired_load_thres_len; i++) {
|
||||
pr_info("paired-load-thres[%d]: %d\n",
|
||||
i, chg->paired_load_thres[i]);
|
||||
}
|
||||
}
|
||||
|
||||
driver = devm_kzalloc(chg->sgm->dev,
|
||||
sizeof(struct mmi_charger_driver),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -2206,6 +2418,7 @@ static int sgm4154x_mmi_charger_init(struct sgm_mmi_charger *chg)
|
|||
driver->is_charge_tapered = sgm4154x_charger_is_charge_tapered;
|
||||
driver->is_charge_halt = sgm4154x_charger_is_charge_halt;
|
||||
driver->set_constraint = sgm4154x_charger_set_constraint;
|
||||
driver->notify_paired_battery = sgm4154x_paired_battery_notify;
|
||||
chg->driver = driver;
|
||||
|
||||
/* register driver to mmi charger */
|
||||
|
|
@ -2363,6 +2576,110 @@ static ssize_t chg_en_show(struct device *dev,
|
|||
}
|
||||
DEVICE_ATTR_RW(chg_en);
|
||||
|
||||
static ssize_t high_load_en_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
bool enable;
|
||||
struct sgm4154x_device *sgm = dev_get_drvdata(dev);
|
||||
|
||||
if (!sgm) {
|
||||
pr_err("sgm chip not valid\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = kstrtobool(buf, &enable);
|
||||
if (ret) {
|
||||
pr_err("Invalid high_load_en value, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(sgm->high_load_en_gpio)) {
|
||||
gpio_set_value(sgm->high_load_en_gpio,
|
||||
enable ^ sgm->high_load_active_low);
|
||||
cancel_delayed_work(&sgm->charge_monitor_work);
|
||||
schedule_delayed_work(&sgm->charge_monitor_work,
|
||||
msecs_to_jiffies(200));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t high_load_en_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
bool enable;
|
||||
struct sgm4154x_device *sgm = dev_get_drvdata(dev);
|
||||
|
||||
if (!sgm) {
|
||||
pr_err("sgm chip not valid\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(sgm->high_load_en_gpio))
|
||||
enable = sgm->high_load_active_low
|
||||
^ gpio_get_value(sgm->high_load_en_gpio);
|
||||
else
|
||||
enable = false;
|
||||
|
||||
return sprintf(buf, "%d\n", enable);
|
||||
}
|
||||
DEVICE_ATTR_RW(high_load_en);
|
||||
|
||||
static ssize_t low_load_en_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
bool enable;
|
||||
struct sgm4154x_device *sgm = dev_get_drvdata(dev);
|
||||
|
||||
if (!sgm) {
|
||||
pr_err("sgm chip not valid\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = kstrtobool(buf, &enable);
|
||||
if (ret) {
|
||||
pr_err("Invalid low_load_en value, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(sgm->low_load_en_gpio)) {
|
||||
gpio_set_value(sgm->low_load_en_gpio,
|
||||
enable ^ sgm->low_load_active_low);
|
||||
cancel_delayed_work(&sgm->charge_monitor_work);
|
||||
schedule_delayed_work(&sgm->charge_monitor_work,
|
||||
msecs_to_jiffies(200));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t low_load_en_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
bool enable;
|
||||
struct sgm4154x_device *sgm = dev_get_drvdata(dev);
|
||||
|
||||
if (!sgm) {
|
||||
pr_err("sgm chip not valid\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(sgm->low_load_en_gpio))
|
||||
enable = gpio_get_value(sgm->low_load_en_gpio)
|
||||
^ sgm->low_load_active_low;
|
||||
else
|
||||
enable = false;
|
||||
|
||||
return sprintf(buf, "%d\n", enable);
|
||||
}
|
||||
DEVICE_ATTR_RW(low_load_en);
|
||||
|
||||
static ssize_t charger_suspend_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
|
|
@ -2530,6 +2847,14 @@ static int sgm4154x_probe(struct i2c_client *client,
|
|||
if (ret)
|
||||
pr_err("Couldn't create chg_en\n");
|
||||
|
||||
ret = device_create_file(sgm->dev, &dev_attr_high_load_en);
|
||||
if (ret)
|
||||
pr_err("Couldn't create high_load_en\n");
|
||||
|
||||
ret = device_create_file(sgm->dev, &dev_attr_low_load_en);
|
||||
if (ret)
|
||||
pr_err("Couldn't create low_load_en\n");
|
||||
|
||||
create_debugfs_entry(sgm);
|
||||
|
||||
dev_info(dev, "%s probe successfully.\n", SGM4154x_NAME);
|
||||
|
|
@ -2547,6 +2872,8 @@ static int sgm4154x_charger_remove(struct i2c_client *client)
|
|||
{
|
||||
struct sgm4154x_device *sgm = i2c_get_clientdata(client);
|
||||
|
||||
device_remove_file(sgm->dev, &dev_attr_high_load_en);
|
||||
device_remove_file(sgm->dev, &dev_attr_low_load_en);
|
||||
device_remove_file(sgm->dev, &dev_attr_chg_en);
|
||||
device_remove_file(sgm->dev, &dev_attr_charger_suspend);
|
||||
debugfs_remove_recursive(sgm->debug_root);
|
||||
|
|
@ -2577,6 +2904,10 @@ static int sgm4154x_charger_remove(struct i2c_client *client)
|
|||
devm_regulator_put(sgm->vdd_i2c_vreg);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(sgm->high_load_en_gpio))
|
||||
gpio_free(sgm->high_load_en_gpio);
|
||||
if (gpio_is_valid(sgm->low_load_en_gpio))
|
||||
gpio_free(sgm->low_load_en_gpio);
|
||||
if (gpio_is_valid(sgm->chg_en_gpio))
|
||||
gpio_free(sgm->chg_en_gpio);
|
||||
|
||||
|
|
|
|||
|
|
@ -286,6 +286,14 @@ struct sgm_mmi_charger {
|
|||
struct mmi_charger_driver *driver;
|
||||
u32 chrg_taper_cnt;
|
||||
struct power_supply *fg_psy;
|
||||
int ichg_polority;
|
||||
|
||||
int paired_ichg;
|
||||
int paired_ichg_table_len;
|
||||
int *paired_ichg_table;
|
||||
int paired_load;
|
||||
int paired_load_thres_len;
|
||||
int *paired_load_thres;
|
||||
};
|
||||
|
||||
struct sgm4154x_device {
|
||||
|
|
@ -327,6 +335,11 @@ struct sgm4154x_device {
|
|||
|
||||
struct dentry *debug_root;
|
||||
|
||||
int high_load_en_gpio;
|
||||
int low_load_en_gpio;
|
||||
bool high_load_active_low;
|
||||
bool low_load_active_low;
|
||||
|
||||
int chg_en_gpio;
|
||||
bool use_ext_usb_psy;
|
||||
struct regulator *vdd_i2c_vreg;
|
||||
|
|
|
|||
Loading…
Reference in a new issue