power: pm8921-charger: disable AICL
There are certain conditions where AICL should be disabled. For example,
cases where a strong usb charger capable of supporting the usb_max_current
or cases where a wireless charger is used.
Use the power supply property HEALTH to indicate whether AICL is desired
or not. If HEALTH is unknown enable AICL, if HEALTH is good disable
AICL.
While at it clean up the vbus_draw callback
- there is no need of the vbus_lock, remove it
- there were , comma separated statements in the probe function, use ;
instead
- the commit to verify the_chip is initialized, defeats the purpose of
remembering the usb current when the_chip is not initialized. Clean
this up
Change-Id: I8b21ccdf5ed69ea917cb370d2e8930c9d8a5003f
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 7478ab9..e4ae96f 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -294,6 +294,7 @@
int btc_delay_ms;
bool btc_panic_if_cant_stop_chg;
int stop_chg_upon_expiry;
+ bool disable_aicl;
};
/* user space parameter to limit usb current */
@@ -1388,6 +1389,7 @@
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_HEALTH,
};
static enum power_supply_property pm_power_props_mains[] = {
@@ -1438,6 +1440,24 @@
return 0;
}
+static int disable_aicl(int disable)
+{
+ if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
+ && disable != POWER_SUPPLY_HEALTH_GOOD) {
+ pr_err("called with invalid param :%d\n", disable);
+ return -EINVAL;
+ }
+
+ if (!the_chip) {
+ pr_err("%s called before init\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("Disable AICL = %d\n", disable);
+ the_chip->disable_aicl = disable;
+ return 0;
+}
+
static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
{
int rc;
@@ -1495,12 +1515,28 @@
break;
case POWER_SUPPLY_PROP_TYPE:
return pm8921_set_usb_power_supply_type(val->intval);
+ case POWER_SUPPLY_PROP_HEALTH:
+ /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
+ return disable_aicl(val->intval);
default:
return -EINVAL;
}
return 0;
}
+static int usb_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_HEALTH:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int pm_power_get_property_usb(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -1535,6 +1571,10 @@
else
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
+ val->intval = the_chip->disable_aicl;
+ break;
default:
return -EINVAL;
}
@@ -1830,7 +1870,6 @@
static void (*notify_vbus_state_func_ptr)(int);
static int usb_chg_current;
-static DEFINE_SPINLOCK(vbus_lock);
int pm8921_charger_register_vbus_sn(void (*callback)(int))
{
@@ -1859,7 +1898,6 @@
}
}
-/* assumes vbus_lock is held */
static void __pm8921_charger_vbus_draw(unsigned int mA)
{
int i, rc;
@@ -1913,15 +1951,10 @@
/* USB calls these to tell us how much max usb current the system can draw */
void pm8921_charger_vbus_draw(unsigned int mA)
{
- unsigned long flags;
+ int set_usb_now_ma;
pr_debug("Enter charge=%d\n", mA);
- if (!the_chip) {
- pr_err("chip not yet initalized\n");
- return;
- }
-
/*
* Reject VBUS requests if USB connection is the only available
* power source. This makes sure that if booting without
@@ -1931,7 +1964,7 @@
* This would also apply when the battery has been
* removed from the running system.
*/
- if (!get_prop_batt_present(the_chip)
+ if (the_chip && !get_prop_batt_present(the_chip)
&& !is_dc_chg_plugged_in(the_chip)) {
if (!the_chip->has_dc_supply) {
pr_err("rejected: no other power source connected\n");
@@ -1950,23 +1983,23 @@
if (usb_target_ma)
usb_target_ma = mA;
- spin_lock_irqsave(&vbus_lock, flags);
- if (the_chip) {
- if (mA > USB_WALL_THRESHOLD_MA)
- __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
- else
- __pm8921_charger_vbus_draw(mA);
- } else {
+
+ if (mA > USB_WALL_THRESHOLD_MA)
+ set_usb_now_ma = USB_WALL_THRESHOLD_MA;
+ else
+ set_usb_now_ma = mA;
+
+ if (the_chip && the_chip->disable_aicl)
+ set_usb_now_ma = mA;
+
+ if (the_chip)
+ __pm8921_charger_vbus_draw(set_usb_now_ma);
+ else
/*
* called before pmic initialized,
* save this value and use it at probe
*/
- if (mA > USB_WALL_THRESHOLD_MA)
- usb_chg_current = USB_WALL_THRESHOLD_MA;
- else
- usb_chg_current = mA;
- }
- spin_unlock_irqrestore(&vbus_lock, flags);
+ usb_chg_current = set_usb_now_ma;
}
EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
@@ -2605,7 +2638,8 @@
* The AICL algorithm will step up the current from 500mA to target
*/
if (is_usb_chg_plugged_in(chip)
- && usb_target_ma > USB_WALL_THRESHOLD_MA) {
+ && usb_target_ma > USB_WALL_THRESHOLD_MA
+ && !chip->disable_aicl) {
/* decrease usb_target_ma */
decrease_usb_ma_value(&usb_target_ma);
/* reset here, increase in unplug_check_worker */
@@ -2868,7 +2902,8 @@
chip->final_kickstart = true;
/* AICL only for usb wall charger */
- if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
+ if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
+ !chip->disable_aicl) {
reg_loop = pm_chg_get_regulation_loop(chip);
pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
if ((reg_loop & VIN_ACTIVE_BIT) &&
@@ -2916,7 +2951,8 @@
/* AICL only for usb wall charger */
if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
&& usb_target_ma > 0
- && !charging_disabled) {
+ && !charging_disabled
+ && !chip->disable_aicl) {
/* only increase iusb_max if vin loop not active */
if (usb_ma < usb_target_ma) {
increase_usb_ma_value(&usb_ma);
@@ -3836,7 +3872,6 @@
/* determines the initial present states */
static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
{
- unsigned long flags;
int fsm_state;
int is_fast_chg;
@@ -3861,12 +3896,16 @@
pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
- spin_lock_irqsave(&vbus_lock, flags);
- if (usb_chg_current) {
- /* reissue a vbus draw call */
- __pm8921_charger_vbus_draw(usb_chg_current);
- }
- spin_unlock_irqrestore(&vbus_lock, flags);
+ if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
+ if (usb_chg_current)
+ /*
+ * Reissue a vbus draw call only if a battery
+ * or DC is present. We don't want to brown out the
+ * device if usb is its only source
+ */
+ __pm8921_charger_vbus_draw(usb_chg_current);
+ usb_chg_current = 0;
+
/*
* The bootloader could have started charging, a fastchg interrupt
* might not happen. Check the real time status and if it is fast
@@ -4730,29 +4769,30 @@
chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
- chip->usb_psy.name = "usb",
- chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
- chip->usb_psy.supplied_to = pm_power_supplied_to,
- chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
- chip->usb_psy.properties = pm_power_props_usb,
- chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
- chip->usb_psy.get_property = pm_power_get_property_usb,
- chip->usb_psy.set_property = pm_power_set_property_usb,
+ chip->usb_psy.name = "usb";
+ chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+ chip->usb_psy.supplied_to = pm_power_supplied_to;
+ chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+ chip->usb_psy.properties = pm_power_props_usb;
+ chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
+ chip->usb_psy.get_property = pm_power_get_property_usb;
+ chip->usb_psy.set_property = pm_power_set_property_usb;
+ chip->usb_psy.property_is_writeable = usb_property_is_writeable;
- chip->dc_psy.name = "pm8921-dc",
- chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
- chip->dc_psy.supplied_to = pm_power_supplied_to,
- chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
- chip->dc_psy.properties = pm_power_props_mains,
- chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
- chip->dc_psy.get_property = pm_power_get_property_mains,
+ chip->dc_psy.name = "pm8921-dc";
+ chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+ chip->dc_psy.supplied_to = pm_power_supplied_to;
+ chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+ chip->dc_psy.properties = pm_power_props_mains;
+ chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
+ chip->dc_psy.get_property = pm_power_get_property_mains;
- chip->batt_psy.name = "battery",
- chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
- chip->batt_psy.properties = msm_batt_power_props,
- chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
- chip->batt_psy.get_property = pm_batt_power_get_property,
- chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
+ chip->batt_psy.name = "battery";
+ chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->batt_psy.properties = msm_batt_power_props;
+ chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
+ chip->batt_psy.get_property = pm_batt_power_get_property;
+ chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
rc = power_supply_register(chip->dev, &chip->usb_psy);
if (rc < 0) {
pr_err("power_supply_register usb failed rc = %d\n", rc);