charger/bq25890: improve charger BC1.2 detection & rerun apsd

improve charger detection
for bq25890

Change-Id: I63d50facde8478b2e8064b44701a1cadbaa92ece
Reviewed-on: https://gerrit.mot.com/2089481
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
gongsc1 2021-10-14 11:54:11 +08:00 • committed by Haijian Ma
commit e2af86a729

View file

@ -133,8 +133,6 @@ struct bq2589x {
struct bq2589x_config cfg;
struct work_struct irq_work;
struct work_struct adapter_in_work;
struct work_struct adapter_out_work;
struct delayed_work monitor_work;
struct delayed_work ico_work;
struct delayed_work pe_volt_tune_work;
@ -544,9 +542,7 @@ int bq2589x_force_dpdm(struct bq2589x *bq)
if (ret)
return ret;
msleep(20);/*TODO: how much time needed to finish dpdm detect?*/
return 0;
}
EXPORT_SYMBOL_GPL(bq2589x_force_dpdm);
@ -1383,23 +1379,40 @@ void bq2589x_set_ilim_enable(struct bq2589x *bq, bool enable)
dev_err(bq->dev, "fail to set ILIM pin ret=%d\n", ret);
}
static int bq2589x_rerun_adsp_if_required(struct bq2589x *bq)
static bool bq2589x_is_rerun_apsd_complete(struct bq2589x *bq)
{
int ret;
u8 val = 0;
bool result = false;
ret = bq2589x_read_byte(bq, &val, BQ2589X_REG_02);
if (ret)
return false;
result = !(val & BQ2589X_FORCE_DPDM_MASK);
pr_info("%s:rerun apsd %s", __func__, result ? "complete" : "not complete");
return result;
}
static int bq2589x_rerun_apsd_if_required(struct bq2589x *bq)
{
int ret = 0;
ret = bq2589x_get_usb_present(bq);
if (ret)
return ret;
if (bq->state.vbus_gd)
if (!bq->state.vbus_gd)
return 0;
ret = bq2589x_reuqest_dpdm(bq, true);
if (ret < 0)
dev_err(bq->dev,"%s:cannot enable DPDM ret=%d\n",__func__, ret);
bq->typec_apsd_rerun_done = true;
bq2589x_force_dpdm(bq);
bq->typec_apsd_rerun_done = true;
dev_info(bq->dev,"rerun apsd done\n");
return 0;
}
@ -1435,76 +1448,49 @@ static void bq2589x_adjust_absolute_vindpm(struct bq2589x *bq)
}
static void bq2589x_vbus_remove(struct bq2589x *bq)
static void bq2589x_adapter_in_func(struct bq2589x *bq)
{
int ret;
dev_err(bq->dev, "Vbus not present, disable charge\n");
bq->typec_apsd_rerun_done = false;
bq->chg_dev->noti.apsd_done = false;
bq->chg_dev->noti.hvdcp_done = false;
bq->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
ret = bq2589x_disable_charger(bq);
if (ret < 0) {
dev_err(bq->dev,"%s:failed to disable charger\n",__func__);
}
bq2589x_reuqest_dpdm(bq, true);
}
static void bq2589x_adapter_in_workfunc(struct work_struct *work)
{
struct bq2589x *bq = container_of(work, struct bq2589x, adapter_in_work);
int ret;
ret = bq2589x_get_usb_present(bq);
if (ret)
return;
if(!bq->state.vbus_gd) {
bq2589x_vbus_remove(bq);
goto vbus_remove;
}
if(!bq->state.online) {
bq2589x_reuqest_dpdm(bq, true);
dev_err(bq->dev, "BC1.2 detect is not done.\n");
goto err;
}
if ((bq->vbus_type == BQ2589X_VBUS_USB_SDP || bq->vbus_type == BQ2589X_VBUS_NONSTAND)
if ((bq->vbus_type == BQ2589X_VBUS_USB_SDP ||
bq->vbus_type == BQ2589X_VBUS_NONSTAND ||
bq->vbus_type == BQ2589X_VBUS_UNKNOWN)
&& (!bq->typec_apsd_rerun_done)) {
dev_err(bq->dev, "rerun apsd for 0x%x\n", bq->vbus_type);
bq->typec_apsd_rerun_done = true;
bq2589x_rerun_adsp_if_required(bq);
goto err;
bq2589x_rerun_apsd_if_required(bq);
return;
}
if (bq->vbus_type == BQ2589X_VBUS_MAXC) {
dev_info(bq->dev, "%s:HVDCP adapter plugged in\n", __func__);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_HVDCP;
schedule_delayed_work(&bq->ico_work, 0);
} else if (bq->vbus_type == BQ2589X_VBUS_USB_CDP) {
dev_info(bq->dev, "%s:CDP plugged in\n", __func__);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_CDP;
schedule_delayed_work(&bq->ico_work, 0);
}else if (bq->vbus_type == BQ2589X_VBUS_USB_DCP) {/* DCP, let's check if it is PE adapter*/
dev_info(bq->dev, "%s:DCP adapter plugged in\n", __func__);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_DCP;
schedule_delayed_work(&bq->check_pe_tuneup_work, 0);
} else if (bq->vbus_type == BQ2589X_VBUS_USB_SDP || bq->vbus_type == BQ2589X_VBUS_UNKNOWN || bq->vbus_type == BQ2589X_VBUS_NONSTAND) {
if (bq->vbus_type == BQ2589X_VBUS_USB_SDP) {
bq->real_charger_type = POWER_SUPPLY_TYPE_USB;
switch (bq->vbus_type) {
case BQ2589X_VBUS_MAXC:
dev_info(bq->dev, "%s:HVDCP adapter plugged in\n", __func__);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_HVDCP;
bq->chg_dev->noti.hvdcp_done = true;
schedule_delayed_work(&bq->ico_work, 0);
break;
case BQ2589X_VBUS_USB_CDP:
dev_info(bq->dev, "%s:CDP plugged in\n", __func__);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_CDP;
break;
case BQ2589X_VBUS_USB_DCP:
dev_info(bq->dev, "%s:DCP adapter plugged in\n", __func__);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_DCP;
schedule_delayed_work(&bq->check_pe_tuneup_work, 0);
break;
case BQ2589X_VBUS_USB_SDP:
dev_info(bq->dev, "%s:SDP plugged in\n", __func__);
} else if (bq->vbus_type == BQ2589X_VBUS_NONSTAND) {
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_FLOAT;
bq->real_charger_type = POWER_SUPPLY_TYPE_USB;
break;
case BQ2589X_VBUS_UNKNOWN:
dev_err(bq->dev, "%s:Unkown adpater plugged in\n", __func__);
case BQ2589X_VBUS_NONSTAND:
dev_info(bq->dev, "%s:NON STAND plugged in\n", __func__);
}else {
dev_info(bq->dev, "%s:unknown adapter plugged in\n", __func__);
}
}
else {
dev_info(bq->dev, "%s:other adapter plugged in,vbus_type is %d\n", __func__, bq->vbus_type);
schedule_delayed_work(&bq->ico_work, 0);
bq->real_charger_type = POWER_SUPPLY_TYPE_USB_FLOAT;
break;
default:
dev_info(bq->dev, "%s:Other adapter %d plugged in\n", __func__, bq->vbus_type);
bq->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
schedule_delayed_work(&bq->ico_work, 0);
break;
}
if (bq->cfg.use_absolute_vindpm)
@ -1515,17 +1501,13 @@ static void bq2589x_adapter_in_workfunc(struct work_struct *work)
}
bq->chg_dev->noti.apsd_done = true;
vbus_remove:
bq->typec_apsd_rerun_done = false;
charger_dev_notify(bq->chg_dev);
err:
return;
}
static void bq2589x_adapter_out_workfunc(struct work_struct *work)
static void bq2589x_adapter_out_func(struct bq2589x *bq)
{
struct bq2589x *bq = container_of(work, struct bq2589x, adapter_out_work);
int ret;
ret = bq2589x_set_input_volt_limit(bq, 4400);
@ -1537,6 +1519,13 @@ static void bq2589x_adapter_out_workfunc(struct work_struct *work)
if (pe.enable) {
cancel_delayed_work_sync(&bq->monitor_work);
}
bq->typec_apsd_rerun_done = false;
bq->chg_dev->noti.apsd_done = false;
bq->chg_dev->noti.hvdcp_done = false;
bq->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
bq2589x_reuqest_dpdm(bq, false);
charger_dev_notify(bq->chg_dev);
}
static void bq2589x_ico_workfunc(struct work_struct *work)
@ -1705,8 +1694,7 @@ static void bq2589x_charger_irq_workfunc(struct work_struct *work)
u8 fault = 0;
u8 charge_status = 0;
int ret;
msleep(5);
bool reapsd_complete = false;
ret = bq2589x_sync_state(bq, &state);
mutex_lock(&bq->lock);
@ -1724,14 +1712,27 @@ static void bq2589x_charger_irq_workfunc(struct work_struct *work)
bq->vbus_type = (status & BQ2589X_VBUS_STAT_MASK) >> BQ2589X_VBUS_STAT_SHIFT;
if (state.vbus_gd && (bq->vbus_type == BQ2589X_VBUS_NONE)){
dev_info(bq->dev, "BC1.2 detect is not done.\n");
bq2589x_reuqest_dpdm(bq, true);
}
if(state.vbus_gd && state.online
&& (bq->typec_apsd_rerun_done == true)
&& (bq->vbus_type != BQ2589X_VBUS_NONE)) {
reapsd_complete = bq2589x_is_rerun_apsd_complete(bq);
}
if (((bq->vbus_type == BQ2589X_VBUS_NONE) || (bq->vbus_type == BQ2589X_VBUS_OTG)) && (bq->status & BQ2589X_STATUS_PLUGIN)) {
dev_info(bq->dev, "%s:adapter removed\n", __func__);
bq->status &= ~BQ2589X_STATUS_PLUGIN;
schedule_work(&bq->adapter_out_work);
} else if (bq->vbus_type != BQ2589X_VBUS_NONE && (bq->vbus_type != BQ2589X_VBUS_OTG) && !(bq->status & BQ2589X_STATUS_PLUGIN)) {
bq2589x_adapter_out_func(bq);
} else if ((bq->vbus_type != BQ2589X_VBUS_NONE) && (bq->vbus_type != BQ2589X_VBUS_OTG)
&& (!(bq->status & BQ2589X_STATUS_PLUGIN) || (reapsd_complete == true))
&& state.online) {
dev_info(bq->dev, "%s:adapter plugged in\n", __func__);
bq->status |= BQ2589X_STATUS_PLUGIN;
schedule_work(&bq->adapter_in_work);
bq2589x_adapter_in_func(bq);
}
@ -2047,8 +2048,6 @@ static int bq2589x_charger_probe(struct i2c_client *client,
bq2589x_set_ilim_enable(bq, false);
INIT_WORK(&bq->irq_work, bq2589x_charger_irq_workfunc);
INIT_WORK(&bq->adapter_in_work, bq2589x_adapter_in_workfunc);
INIT_WORK(&bq->adapter_out_work, bq2589x_adapter_out_workfunc);
INIT_DELAYED_WORK(&bq->monitor_work, bq2589x_monitor_workfunc);
INIT_DELAYED_WORK(&bq->ico_work, bq2589x_ico_workfunc);
INIT_DELAYED_WORK(&bq->pe_volt_tune_work, bq2589x_tune_volt_workfunc);
@ -2061,12 +2060,6 @@ static int bq2589x_charger_probe(struct i2c_client *client,
goto err_irq;
}
ret = bq2589x_rerun_adsp_if_required(bq);
if (ret) {
dev_err(dev, "failed to rerun adsp. err: %d\n", ret);
goto err_irq;
}
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq2589x_charger_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, BQ25890_IRQ_PIN, bq);
if (ret) {
@ -2077,13 +2070,13 @@ static int bq2589x_charger_probe(struct i2c_client *client,
}
pe.enable = false;
schedule_work(&bq->irq_work);/*in case of adapter has been in when power off*/
bq2589x_rerun_apsd_if_required(bq);
return 0;
err_irq:
cancel_work_sync(&bq->irq_work);
cancel_work_sync(&bq->adapter_in_work);
cancel_work_sync(&bq->adapter_out_work);
cancel_delayed_work_sync(&bq->ico_work);
cancel_delayed_work_sync(&bq->check_pe_tuneup_work);
if (pe.enable) {
@ -2109,8 +2102,6 @@ static void bq2589x_charger_shutdown(struct i2c_client *client)
sysfs_remove_group(&bq->dev->kobj, &bq2589x_attr_group);
cancel_work_sync(&bq->irq_work);
cancel_work_sync(&bq->adapter_in_work);
cancel_work_sync(&bq->adapter_out_work);
cancel_delayed_work_sync(&bq->ico_work);
cancel_delayed_work_sync(&bq->check_pe_tuneup_work);
if (pe.enable) {