Revert "Revert (CR) power:fet_control Vbatt2 balance path"

Re-instate the original commit back into mainline to validate.

This reverts commit e5433a437a06221b577d0b54c4e4936d317e4c1e.

Change-Id: Ida06a55eee333d31fb0f0f212daed74c11c790b9
Reviewed-on: https://gerrit.mot.com/2118107
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Bernie Moreno <berniem@motorola.com>
Reviewed-by: Ling Jin <lingjin@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Sridhar Vashist 2021-11-16 11:26:05 -06:00
commit d693f3b415

View file

@ -35,19 +35,20 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/iio/consumer.h>
#define RBALANCE_VDIFF_MV 100
#define MAIN_MV_MID_LO 3600
#define MAIN_MV_MID_HI 3800
#define MAIN_CURR_SWITCH 500
#define RBALANCE_VDIFF_MV 200
#define GPIO_SET_DELAY 50
#define CHRG_FULLCURR_EN 1
#define CHRG_FULLCURR_DIS 0
#define HBDLY_DISCHARGE_MS 30000
#define HBDLY_CHARGE_MS 6000
static struct fet_control_data {
struct device *dev;
struct power_supply *main_batt_psy;
struct power_supply *usb_psy;
struct notifier_block ps_notif;
struct delayed_work update;
bool init_done;
bool ps_is_present;
@ -56,11 +57,14 @@ static struct fet_control_data {
int battplus_en_gpio;
int balance_en_n_gpio;
int chrg_fullcurr_en_gpio;
int vbus_ocp_fault_n_gpio;
struct iio_channel *vbatt2_sns_chan;
} fetControlData;
int battplus_state = -1;
int balance_state = -1;
int fullcurr_state = -1;
int ocp_fault_n_state = -1;
static int get_ps_int_prop(struct power_supply *psy, enum power_supply_property prop)
{
@ -179,6 +183,32 @@ static int set_fullcurr_state(const char *val, const struct kernel_param *kp)
return 0;
}
static int set_ocp_fault_n_state(const char *val, const struct kernel_param *kp)
{
int rc;
long mode;
if (!fetControlData.init_done)
return -ENODEV;
rc = kstrtol(val, 0, &mode);
if (rc)
return rc;
rc = update_state_gpio(fetControlData.vbus_ocp_fault_n_gpio, !!mode);
if (rc) {
pr_err("Update fet-ctl gpio [%d] failed\n", fetControlData.vbus_ocp_fault_n_gpio);
return rc;
} else {
fullcurr_state = !!mode;
pr_debug("Set using vbus_ocp_fault_n gpio[%d], VAL:[%d]\n",
fetControlData.vbus_ocp_fault_n_gpio,
gpio_get_value(fetControlData.vbus_ocp_fault_n_gpio));
}
return 0;
}
static struct kernel_param_ops battplus_ops =
{
.set = &set_battplus_state,
@ -197,6 +227,12 @@ static struct kernel_param_ops fullcurr_ops =
.get = param_get_int,
};
static struct kernel_param_ops ocpfault_ops =
{
.set = &set_ocp_fault_n_state,
.get = param_get_int,
};
module_param_cb(battplus_state,
&battplus_ops,
&battplus_state,
@ -215,72 +251,182 @@ module_param_cb(fullcurr_state,
S_IRUGO | S_IWUSR
);
module_param_cb(ocp_fault_n_state,
&ocpfault_ops,
&ocp_fault_n_state,
S_IRUGO | S_IWUSR
);
static int mmi_is_factory(void)
{
const char *bootargs_str = NULL;
char *kvpair = NULL;
char *value = NULL;
int ret = -1;
struct device_node *n = of_find_node_by_path("/chosen");
size_t bootargs_str_len = 0;
if (n == NULL)
goto ret;
if (of_property_read_string(n, "mmi,bootconfig", &bootargs_str) != 0)
goto putnode;
bootargs_str_len = strlen(bootargs_str);
kvpair = strnstr(bootargs_str, "androidboot.mode=", strlen(bootargs_str));
if (kvpair) { // found key
value = strchr(kvpair, '=') + 1;
if (!strncmp(value, "mot-factory", 11))
ret = 1;
else
ret = 0;
}
putnode:
of_node_put(n);
ret:
return ret;
}
static void update_work(struct work_struct *work)
{
struct fet_control_data *data = container_of(work, struct fet_control_data, update.work);
int main_curr, main_mv;
int main_dischg = -1;
int main_curr, main_mv, flip_mv = 0, usbtype;
int main_chg = 1, rc = 0;
int hb_sched_time = HBDLY_DISCHARGE_MS;
int vbatt2_sns_uv = -EINVAL;
const char * usb_types[] = {"UNKNOWN","SDP","DCP","CDP","ACA","Type-C","PD","PD_DRP"};
fullcurr_state = CHRG_FULLCURR_EN;
if (battplus_state) {
pr_info("BATTFET Closed- Ending Work..\n");
fullcurr_state = CHRG_FULLCURR_DIS;
usbtype = get_ps_int_prop(data->usb_psy,
POWER_SUPPLY_PROP_USB_TYPE);
pr_info("USB-TYPE found:%d [%s]\n", usbtype,usb_types[usbtype] );
/* For no Charger connected & battfet already closed, nothing more to be done */
if (mmi_is_factory()) {
pr_err("Factory Mode- Cancel Work.. \n");
cancel_delayed_work(&data->update);
return;
} else if (usbtype == POWER_SUPPLY_USB_TYPE_UNKNOWN && battplus_state) {
pr_err("BATTFET Closed & Not Charging- Cancel Work..\n");
cancel_delayed_work(&data->update);
return;
}
/*flip_mv = get_ps_int_prop(data->flip_batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW);
flip_mv /= 1000;*/
/* VMain in mV */
main_mv = get_ps_int_prop(data->main_batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW);
main_mv /= 1000;
/* Main current sysfs already in mA */
/* Main current in uA */
main_curr = get_ps_int_prop(data->main_batt_psy,
POWER_SUPPLY_PROP_CURRENT_NOW);
if (main_curr > 0) {
if (main_curr > 0)
pr_info("Charging Main\n");
main_dischg = 1;
}
else
main_chg = -1;
data->main_chg_curr_max = get_ps_int_prop(data->main_batt_psy,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN);
data->main_chg_curr_max /= 1000;
if (data->main_chg_curr_max < 0) {
pr_err("Failed to get Main Max chrg curr\n");
return;
}
ocp_fault_n_state = gpio_get_value(fetControlData.vbus_ocp_fault_n_gpio);
pr_info("ocp_fault_n GPIO:[%d], VAL:[%d]\n",
fetControlData.vbus_ocp_fault_n_gpio, ocp_fault_n_state);
/* Leave FULLCURR_DIS until charger is connected */
if (usbtype != POWER_SUPPLY_USB_TYPE_UNKNOWN) {
if ( (main_chg * main_curr > data->main_chg_curr_max / 2) ||
!ocp_fault_n_state ) {
fullcurr_state = CHRG_FULLCURR_DIS;
pr_err("WARNING! Main-OC or OCP-TRIP: Main_curr:%d, ocp_fault_n:%d\n",
main_curr, ocp_fault_n_state);
} else {
fullcurr_state = CHRG_FULLCURR_EN;
}
}
/* Read the ADC pm8350b_vbatt2_sns div3, scale *3 and to mV */
rc = iio_read_channel_processed(fetControlData.vbatt2_sns_chan, &vbatt2_sns_uv);
if (rc < 0) {
pr_err("Error Reading pm8350b_vbatt2_sns_voltage- rc:%d\n", rc);
return;
} else {
pr_info("SUCCESS reading pm8350b_vbatt2_sns_voltage- VAL-uV:%d\n", vbatt2_sns_uv);
flip_mv = (3 * vbatt2_sns_uv) / 1000;
}
pr_info("Main_curr:%d, main_Ichg_MAX:%d\n",
main_curr, data->main_chg_curr_max);
pr_info("Flip-Vbatt: --, Main-Vbatt: %d\n", main_mv);
pr_err("Flip-Vbatt: %d, Main-Vbatt: %d\n", flip_mv, main_mv);
/* FET paths set in Batt discharge state */
if (main_dischg == -1) {
if (main_chg == -1) {
/* Leave Balance dflt-en & toggle in/out parallel low-Z battplus fet */
balance_state = 0;
/*if ((main_mv - flip_mv) < RBALANCE_VDIFF_MV) {
battplus_state = 1;*/
if ( (main_mv >= MAIN_MV_MID_LO && main_mv <= MAIN_MV_MID_HI) &&
(main_dischg * main_curr/1000 < MAIN_CURR_SWITCH) ) {
if ((main_mv - flip_mv) < RBALANCE_VDIFF_MV) {
battplus_state = 1;
pr_info("battplus-EN: %d\n", battplus_state);
} else {
battplus_state = 0;
pr_info("battplus-DIS: %d\n", battplus_state);
schedule_delayed_work(&data->update, msecs_to_jiffies(hb_sched_time));
}
} else { // Full Charging
hb_sched_time = HBDLY_CHARGE_MS;
pr_info("FASTCHG\n");
}
/* Update GPIO controls */
update_state_gpio(fetControlData.battplus_en_gpio, battplus_state);
update_state_gpio(fetControlData.balance_en_n_gpio, balance_state);
update_state_gpio(fetControlData.chrg_fullcurr_en_gpio, fullcurr_state);
//update_state_gpio(fetControlData.vbus_ocp_fault_n_gpio, ocp_fault_n_state);
schedule_delayed_work(&data->update, msecs_to_jiffies(hb_sched_time));
}
static int ps_notify_callback(struct notifier_block *nb,
unsigned long event, void *p)
{
struct fet_control_data *data = container_of(nb, struct fet_control_data, ps_notif);
struct power_supply *psy = p;
union power_supply_propval pval = {0};
int retval;
bool present_ps;
if ((event == PSY_EVENT_PROP_CHANGED) &&
psy && psy->desc->get_property && psy->desc->name &&
!strncmp(psy->desc->name, "usb", sizeof("usb")) && data) {
pr_info("psy notif: event = %lu\n", event);
retval = power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE,
&pval);
if (retval) {
pr_err("%s psy get property failed, ERR: %d\n", psy->desc->name, retval);
return retval;
}
present_ps = (pval.intval) ? true : false;
pr_info("%s is %s\n", psy->desc->name,
(present_ps) ? "present" : "not present");
if (event == PSY_EVENT_PROP_CHANGED) {
if (data->ps_is_present == present_ps) {
pr_info("ps present state unchanged\n");
return 0;
}
}
data->ps_is_present = present_ps;
cancel_delayed_work(&data->update);
schedule_delayed_work(&data->update, msecs_to_jiffies(3000));
}
return 0;
}
static int parse_dt(struct device_node *node)
{
@ -291,7 +437,7 @@ static int parse_dt(struct device_node *node)
if (!rc && main_batt_psy_name) {
fetControlData.main_batt_psy = power_supply_get_by_name(main_batt_psy_name);
if (!fetControlData.main_batt_psy) {
pr_debug("Could not get flip batt psy and main batt psy, maybe we are early - defer.");
pr_debug("Could not get main batt psy, maybe we are early - defer.");
return -EPROBE_DEFER;
}
}
@ -317,6 +463,13 @@ static int parse_dt(struct device_node *node)
return -ENODEV;
}
fetControlData.vbus_ocp_fault_n_gpio = of_get_named_gpio(node,
"mmi,vbus-ocp-fault-n-gpio", 0);
if (!gpio_is_valid(fetControlData.vbus_ocp_fault_n_gpio)) {
pr_err("ocp-fault-gpio is not valid!\n");
return -ENODEV;
}
return rc;
}
@ -334,6 +487,21 @@ static int fet_control_probe(struct platform_device *pdev)
goto fail;
}
fetControlData.usb_psy = power_supply_get_by_name("usb");
if (!fetControlData.usb_psy) {
pr_debug("Could not get usb psy, maybe we are early - defer.");
return -EPROBE_DEFER;
}
/* Get the ADC device instance pm8350b_vbatt2_sns, gpio3_pu0_div3 */
fetControlData.vbatt2_sns_chan = iio_channel_get(fetControlData.dev, "pm8350b_vbatt2_sns");
if (!fetControlData.vbatt2_sns_chan) {
pr_err("Error Getting pm8350b_vbatt2_sns_voltage channel- rc:%d\n",rc);
return -EINVAL;
} else {
pr_info("Found pm8350b_vbatt2_sns voltage channel\n");
}
rc = gpio_request(fetControlData.battplus_en_gpio, "mmi,flip_battplus_en_gpio");
if (rc) {
pr_err("Failed request battplus_en_gpio\n");
@ -352,6 +520,12 @@ static int fet_control_probe(struct platform_device *pdev)
goto fail;
}
rc = gpio_request(fetControlData.vbus_ocp_fault_n_gpio, "mmi,vbus-ocp-fault-n-gpio");
if (rc) {
pr_err("Failed request vbus-ocp-fault-n-gpio\n");
goto fail;
}
/* Set default Flip Battery Path FETs: battplus path disable*/
rc = gpio_direction_output(fetControlData.battplus_en_gpio, 0); //Path Disabled
if (rc) {
@ -374,7 +548,14 @@ static int fet_control_probe(struct platform_device *pdev)
pr_err("Unable to set DIR/VAL chrg_fullcurr_en_gpio [%d]\n", fetControlData.chrg_fullcurr_en_gpio);
goto fail;
}
fullcurr_state = CHRG_FULLCURR_EN;
fullcurr_state = CHRG_FULLCURR_DIS;
/* Set OCP_FAULT input */
rc = gpio_direction_input(fetControlData.vbus_ocp_fault_n_gpio);
if (rc) {
pr_err("Unable to set DIR vbus_ocp_fault_n [%d]\n", fetControlData.vbus_ocp_fault_n_gpio);
goto fail;
}
pr_info("Flip_battplus_en Init GPIO:[%d], VAL:[%d]\n",
fetControlData.battplus_en_gpio,
@ -385,6 +566,16 @@ static int fet_control_probe(struct platform_device *pdev)
pr_info("chrg_fullcurr Init GPIO:[%d], VAL:[%d]\n",
fetControlData.chrg_fullcurr_en_gpio,
gpio_get_value(fetControlData.chrg_fullcurr_en_gpio) );
pr_info("ocp_fault_n Init GPIO:[%d], VAL:[%d]\n",
fetControlData.vbus_ocp_fault_n_gpio,
gpio_get_value(fetControlData.vbus_ocp_fault_n_gpio) );
// Notify on plug/unplug
fetControlData.ps_notif.notifier_call = ps_notify_callback;
if (power_supply_reg_notifier(&fetControlData.ps_notif)) {
pr_err("Failed to register notifier\n");
goto fail;
}
// Work to update the fet & charge current states.
INIT_DELAYED_WORK(&fetControlData.update, update_work);
@ -401,9 +592,11 @@ static int fet_control_remove(struct platform_device *pdev)
if (fetControlData.init_done) {
cancel_delayed_work(&fetControlData.update);
power_supply_unreg_notifier(&fetControlData.ps_notif);
gpio_free(fetControlData.battplus_en_gpio);
gpio_free(fetControlData.balance_en_n_gpio);
gpio_free(fetControlData.chrg_fullcurr_en_gpio);
gpio_free(fetControlData.vbus_ocp_fault_n_gpio);
}
return 0;