power: supply: bq25890: add pd charge support

Signed-off-by: Shunqing Chen <csq@rock-chips.com>
Change-Id: I3597b7e1934396a2e3d29f314fac50d476a46a23
This commit is contained in:
Shunqing Chen
2021-12-14 15:42:32 +08:00
committed by Tao Huang
parent 2a5891beb5
commit ed37307abb

View File

@@ -116,6 +116,13 @@ struct bq25890_device {
struct bq25890_init_data init_data;
struct bq25890_state state;
struct workqueue_struct *charger_wq;
struct delayed_work pd_work;
struct notifier_block nb;
struct device_node *notify_node;
int pd_vol;
int pd_cur;
struct mutex lock; /* protect state data */
};
@@ -265,6 +272,7 @@ enum bq25890_table_ids {
TBL_SYSVMIN,
TBL_VBATCOMP,
TBL_RBATCOMP,
TBL_VINDPM,
/* lookup tables */
TBL_TREG,
@@ -308,6 +316,7 @@ static const union {
[TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */
[TBL_VBATCOMP] ={ .rt = {0, 224000, 32000} }, /* uV */
[TBL_RBATCOMP] ={ .rt = {0, 140000, 20000} }, /* uOhm */
[TBL_VINDPM] = { .rt = {100000, 3100000, 100000} }, /* uV */
/* lookup tables */
[TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
@@ -736,6 +745,7 @@ static int bq25890_power_supply_init(struct bq25890_device *bq)
psy_cfg.supplied_to = bq25890_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
psy_cfg.of_node = bq->dev->of_node;
bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc,
&psy_cfg);
@@ -914,6 +924,152 @@ static int bq25890_fw_probe(struct bq25890_device *bq)
init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
bq->notify_node = of_parse_phandle(bq->dev->of_node,
"ti,usb-charger-detection", 0);
return 0;
}
static void bq25890_set_pd_param(struct bq25890_device *bq, int vol, int cur)
{
int vindpm, iilim, ichg, vol_limit;
int i = 0;
iilim = bq25890_find_idx(cur, TBL_IILIM);
ichg = bq25890_find_idx(cur, TBL_ICHG);
vol_limit = vol;
if (vol < 5000000)
vol_limit = 5000000;
vol_limit = vol_limit - 1280000 - 3200000;
if (vol > 6000000)
vol_limit /= 2;
vindpm = bq25890_find_idx(vol_limit, TBL_VINDPM);
while (!bq25890_field_read(bq, F_PG_STAT) && i < 5) {
msleep(500);
i++;
}
bq25890_field_write(bq, F_IILIM, iilim);
bq25890_field_write(bq, F_VINDPM_OFS, vindpm);
bq25890_field_write(bq, F_ICHG, ichg);
dev_info(bq->dev, "vol=%d cur=%d INPUT_CURRENT:%x, INPUT_VOLTAGE:%x, CHARGE_CURRENT:%x\n",
vol, cur, iilim, vindpm, ichg);
bq25890_get_chip_state(bq, &bq->state);
power_supply_changed(bq->charger);
}
static int bq25890_pd_notifier_call(struct notifier_block *nb,
unsigned long val, void *v)
{
struct bq25890_device *bq =
container_of(nb, struct bq25890_device, nb);
struct power_supply *psy = v;
union power_supply_propval prop;
int ret;
if (val != PSY_EVENT_PROP_CHANGED)
return NOTIFY_OK;
/* Ignore event if it was not send by notify_node/notify_device */
if (bq->notify_node) {
if (!psy->dev.parent ||
psy->dev.parent->of_node != bq->notify_node)
return NOTIFY_OK;
}
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &prop);
if (ret != 0)
return NOTIFY_OK;
/* online=0: USB out */
if (prop.intval == 0) {
bq->pd_cur = 450000;
bq->pd_vol = 5000000;
queue_delayed_work(bq->charger_wq, &bq->pd_work,
msecs_to_jiffies(10));
return NOTIFY_OK;
}
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop);
if (ret != 0)
return NOTIFY_OK;
bq->pd_cur = prop.intval;
if (bq->pd_cur > 0) {
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,
&prop);
if (ret != 0)
return NOTIFY_OK;
bq->pd_vol = prop.intval;
queue_delayed_work(bq->charger_wq, &bq->pd_work,
msecs_to_jiffies(100));
}
return NOTIFY_OK;
}
static void bq25890_pd_evt_worker(struct work_struct *work)
{
struct bq25890_device *bq = container_of(work,
struct bq25890_device,
pd_work.work);
bq25890_set_pd_param(bq, bq->pd_vol, bq->pd_cur);
}
static int bq25890_register_pd_psy(struct bq25890_device *bq)
{
struct power_supply *notify_psy = NULL;
union power_supply_propval prop;
int ret;
if (!bq->notify_node)
return -EINVAL;
bq->charger_wq = alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM |
WQ_FREEZABLE,
"bq25890-charge-wq");
INIT_DELAYED_WORK(&bq->pd_work,
bq25890_pd_evt_worker);
bq->nb.notifier_call = bq25890_pd_notifier_call;
ret = power_supply_reg_notifier(&bq->nb);
if (ret) {
dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
return ret;
}
if (bq->nb.notifier_call) {
notify_psy = power_supply_get_by_phandle(bq->dev->of_node,
"ti,usb-charger-detection");
if (IS_ERR_OR_NULL(notify_psy)) {
dev_info(bq->dev, "bq25700 notify_psy is error\n");
notify_psy = NULL;
}
}
if (notify_psy) {
ret = power_supply_get_property(notify_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&prop);
if (ret != 0)
return ret;
bq->pd_cur = prop.intval;
ret = power_supply_get_property(notify_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
&prop);
if (ret != 0)
return ret;
bq->pd_vol = prop.intval;
queue_delayed_work(bq->charger_wq, &bq->pd_work,
msecs_to_jiffies(10));
}
return 0;
}
@@ -1005,6 +1161,8 @@ static int bq25890_probe(struct i2c_client *client,
goto irq_fail;
}
bq25890_register_pd_psy(bq);
return 0;
irq_fail: