Skip to content

Commit c688e0c

Browse files
Marek Vasutsre
authored andcommitted
power: supply: bq25890: Add HiZ mode support
The bq25890 is capable of disconnecting itself from the external supply, in which case the system is supplied only from the battery. This can be useful e.g. to test the pure battery operation, or draw no power from USB port. Implement support for this mode, which can be toggled by writing 0 or non-zero to sysfs 'online' attribute, to select either offline or online mode. The IRQ handler has to be triggered to update chip state, as switching to and from HiZ mode does not generate an interrupt automatically. The IRQ handler reinstates the HiZ mode in case a cable is replugged by the user, the chip itself clears the HiZ mode bit when cable is plugged in by the user and the chip detects PG bad-to-good transition. Signed-off-by: Marek Vasut <marex@denx.de> [hdegoede@redhat.com: Replace "&" with "&&" in a boolean check] Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
1 parent d1b2509 commit c688e0c

1 file changed

Lines changed: 44 additions & 14 deletions

File tree

drivers/power/supply/bq25890_charger.c

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct bq25890_init_data {
9595

9696
struct bq25890_state {
9797
u8 online;
98+
u8 hiz;
9899
u8 chrg_status;
99100
u8 chrg_fault;
100101
u8 vsys_status;
@@ -119,6 +120,7 @@ struct bq25890_device {
119120

120121
bool skip_reset;
121122
bool read_back_init_data;
123+
bool force_hiz;
122124
u32 pump_express_vbus_max;
123125
enum bq25890_chip_version chip_version;
124126
struct bq25890_init_data init_data;
@@ -487,7 +489,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
487489

488490
switch (psp) {
489491
case POWER_SUPPLY_PROP_STATUS:
490-
if (!state.online)
492+
if (!state.online || state.hiz)
491493
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
492494
else if (state.chrg_status == STATUS_NOT_CHARGING)
493495
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -502,7 +504,8 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
502504
break;
503505

504506
case POWER_SUPPLY_PROP_CHARGE_TYPE:
505-
if (!state.online || state.chrg_status == STATUS_NOT_CHARGING ||
507+
if (!state.online || state.hiz ||
508+
state.chrg_status == STATUS_NOT_CHARGING ||
506509
state.chrg_status == STATUS_TERMINATION_DONE)
507510
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
508511
else if (state.chrg_status == STATUS_PRE_CHARGING)
@@ -522,7 +525,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
522525
break;
523526

524527
case POWER_SUPPLY_PROP_ONLINE:
525-
val->intval = state.online;
528+
val->intval = state.online && !state.hiz;
526529
break;
527530

528531
case POWER_SUPPLY_PROP_HEALTH:
@@ -676,7 +679,8 @@ static int bq25890_power_supply_set_property(struct power_supply *psy,
676679
const union power_supply_propval *val)
677680
{
678681
struct bq25890_device *bq = power_supply_get_drvdata(psy);
679-
int maxval;
682+
struct bq25890_state state;
683+
int maxval, ret;
680684
u8 lval;
681685

682686
switch (psp) {
@@ -691,6 +695,12 @@ static int bq25890_power_supply_set_property(struct power_supply *psy,
691695
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
692696
lval = bq25890_find_idx(val->intval, TBL_IINLIM);
693697
return bq25890_field_write(bq, F_IINLIM, lval);
698+
case POWER_SUPPLY_PROP_ONLINE:
699+
ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval);
700+
if (!ret)
701+
bq->force_hiz = !val->intval;
702+
bq25890_update_state(bq, psp, &state);
703+
return ret;
694704
default:
695705
return -EINVAL;
696706
}
@@ -703,6 +713,7 @@ static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
703713
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
704714
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
705715
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
716+
case POWER_SUPPLY_PROP_ONLINE:
706717
return true;
707718
default:
708719
return false;
@@ -757,6 +768,7 @@ static int bq25890_get_chip_state(struct bq25890_device *bq,
757768
} state_fields[] = {
758769
{F_CHG_STAT, &state->chrg_status},
759770
{F_PG_STAT, &state->online},
771+
{F_EN_HIZ, &state->hiz},
760772
{F_VSYS_STAT, &state->vsys_status},
761773
{F_BOOST_FAULT, &state->boost_fault},
762774
{F_BAT_FAULT, &state->bat_fault},
@@ -772,10 +784,11 @@ static int bq25890_get_chip_state(struct bq25890_device *bq,
772784
*state_fields[i].data = ret;
773785
}
774786

775-
dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
776-
state->chrg_status, state->online, state->vsys_status,
777-
state->chrg_fault, state->boost_fault, state->bat_fault,
778-
state->ntc_fault);
787+
dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
788+
state->chrg_status, state->online,
789+
state->hiz, state->vsys_status,
790+
state->chrg_fault, state->boost_fault,
791+
state->bat_fault, state->ntc_fault);
779792

780793
return 0;
781794
}
@@ -792,16 +805,33 @@ static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
792805
if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
793806
return IRQ_NONE;
794807

795-
if (!new_state.online && bq->state.online) { /* power removed */
808+
/* power removed or HiZ */
809+
if ((!new_state.online || new_state.hiz) && bq->state.online) {
796810
/* disable ADC */
797811
ret = bq25890_field_write(bq, F_CONV_RATE, 0);
798812
if (ret < 0)
799813
goto error;
800-
} else if (new_state.online && !bq->state.online) { /* power inserted */
801-
/* enable ADC, to have control of charge current/voltage */
802-
ret = bq25890_field_write(bq, F_CONV_RATE, 1);
803-
if (ret < 0)
804-
goto error;
814+
} else if (new_state.online && !bq->state.online) {
815+
/*
816+
* Restore HiZ bit in case it was set by user.
817+
* The chip does not retain this bit once the
818+
* cable is re-plugged, hence the bit must be
819+
* reset manually here.
820+
*/
821+
if (bq->force_hiz) {
822+
ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz);
823+
if (ret < 0)
824+
goto error;
825+
new_state.hiz = 1;
826+
}
827+
828+
if (!new_state.hiz) {
829+
/* power inserted and not HiZ */
830+
/* enable ADC, to have control of charge current/voltage */
831+
ret = bq25890_field_write(bq, F_CONV_RATE, 1);
832+
if (ret < 0)
833+
goto error;
834+
}
805835
}
806836

807837
bq->state = new_state;

0 commit comments

Comments
 (0)