On Tue, Sep 25, 2012 at 10:12:34AM -0600, mathieu.poir...@linaro.org wrote: > From: Kalle Komierowski <karl.komierow...@stericsson.com> > > Due to a bug in some AB8500 ASICs charger removal cannot always > be detected if the removal and reinsertion is done to close in time. > This patch detects above described case and handles the situation > so that charging will be kept turned on. > > Signed-off-by: Kalle Komierowski <karl.komierow...@stericsson.com> > Signed-off-by: Mathieu Poirier <mathieu.poir...@linaro.org> > Reviewed-by: Marcus COOPER <marcus.xm.coo...@stericsson.com> > Reviewed-by: Jonas ABERG <jonas.ab...@stericsson.com> > Reviewed-by: Philippe LANGLAIS <philippe.langl...@stericsson.com> > --- > drivers/power/ab8500_charger.c | 105 > ++++++++++++++++++++++++++++- > drivers/power/abx500_chargalg.c | 31 ++++++++- > include/linux/mfd/abx500/ux500_chargalg.h | 1 + > 3 files changed, 134 insertions(+), 3 deletions(-) > > diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c > index 8137ea5..70e7c5e 100644 > --- a/drivers/power/ab8500_charger.c > +++ b/drivers/power/ab8500_charger.c > @@ -49,6 +49,7 @@ > #define VBUS_DET_DBNC100 0x02 > #define VBUS_DET_DBNC1 0x01 > #define OTP_ENABLE_WD 0x01 > +#define DROP_COUNT_RESET 0x01 > > #define MAIN_CH_INPUT_CURR_SHIFT 4 > #define VBUS_IN_CURR_LIM_SHIFT 4 > @@ -1672,6 +1673,105 @@ static int ab8500_charger_usb_en(struct ux500_charger > *charger, > } > > /** > + * ab8500_charger_usb_check_enable() - enable usb charging > + * @charger: pointer to the ux500_charger structure > + * @vset: charging voltage > + * @iset: charger output current > + * > + * Check if the VBUS charger has been disconnected and reconnected without > + * AB8500 rising an interrupt. Returns 0 on success. > + */ > +static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, > + int vset, int iset)
Wrong indentation (should be at least two tabs; sometimes the driver aligning to opening parenthesis, sometimes not... it's better to be consistent). > +{ > + u8 usbch_ctrl1 = 0; > + int ret = 0; > + No need for this empty line. > + struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); > + > + if (!di->usb.charger_connected) > + return ret; > + > + ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, > + AB8500_USBCH_CTRL1_REG, &usbch_ctrl1); > + if (ret < 0) { > + dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); > + return ret; > + } > + dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1); > + > + if (!(usbch_ctrl1 & USB_CH_ENA)) { By returning early you can greatly reduce indentation and make the code more readable. if (usbch_ctrl1 & USB_CH_ENA) return ret; ...the rest... > + dev_info(di->dev, "Charging has been disabled abnormally and > will be re-enabled\n"); > + > + ret = abx500_mask_and_set_register_interruptible(di->dev, > + AB8500_CHARGER, AB8500_CHARGER_CTRL, > + DROP_COUNT_RESET, DROP_COUNT_RESET); > + if (ret < 0) { > + dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); > + return ret; > + } > + > + ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset); > + if (ret < 0) { > + dev_err(di->dev, "Failed to enable VBUS charger %d\n", > + __LINE__); > + return ret; > + } > + } > + return ret; > +} > + > +/** > + * ab8500_charger_ac_check_enable() - enable usb charging > + * @charger: pointer to the ux500_charger structure > + * @vset: charging voltage > + * @iset: charger output current > + * > + * Check if the AC charger has been disconnected and reconnected without > + * AB8500 rising an interrupt. Returns 0 on success. > + */ > +static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, > + int vset, int iset) This function is very very similar to the previous one. The only difference seem to be whether you use MAIN_CH_ENA or USB_CH_ENA.. So would it make sense to introduce a helper function that accepts one additional parameter: ab8500_charger_check_enable(....., int ch_ena) ? [...] > +static int abx500_chargalg_check_charger_enable(struct abx500_chargalg *di) > +{ > + switch (di->charge_state) { > + case STATE_NORMAL: > + case STATE_MAINTENANCE_A: > + case STATE_MAINTENANCE_B: > + break; > + default: > + return 0; > + } > + > + if (di->chg_info.charger_type & USB_CHG) { > + return di->usb_chg->ops.check_enable(di->usb_chg, > + di->bat->bat_type[di->bat->batt_id].normal_vol_lvl, > + di->bat->bat_type[di->bat->batt_id].normal_cur_lvl); > + } else if (di->chg_info.charger_type & AC_CHG) { > + return di->ac_chg->ops.check_enable(di->ac_chg, > + di->bat->bat_type[di->bat->batt_id].normal_vol_lvl, > + di->bat->bat_type[di->bat->batt_id].normal_cur_lvl); di->bat is very repetative, and can be avoided by introducing a variable. (Not that it would greatly help readability, but a little, yes.) > + } > + return -ENXIO; > +} > + > /** > * abx500_chargalg_check_charger_connection() - Check charger connection > change > * @di: pointer to the abx500_chargalg structure > @@ -1220,6 +1243,7 @@ static void > abx500_chargalg_external_power_changed(struct power_supply *psy) > static void abx500_chargalg_algorithm(struct abx500_chargalg *di) > { > int charger_status; > + int ret; > > /* Collect data from all power_supply class devices */ > class_for_each_device(power_supply_class, NULL, > @@ -1228,8 +1252,13 @@ static void abx500_chargalg_algorithm(struct > abx500_chargalg *di) > abx500_chargalg_end_of_charge(di); > abx500_chargalg_check_temp(di); > abx500_chargalg_check_charger_voltage(di); > - Stray change. > charger_status = abx500_chargalg_check_charger_connection(di); > + > + ret = abx500_chargalg_check_charger_enable(di); > + if (ret < 0) > + dev_err(di->dev, "Checking charger if enabled error: %d line: > %d\n", > + ret, __LINE__); > + > /* > * First check if we have a charger connected. > * Also we don't allow charging of unknown batteries if configured > diff --git a/include/linux/mfd/abx500/ux500_chargalg.h > b/include/linux/mfd/abx500/ux500_chargalg.h > index d43ac0f..110d12f 100644 > --- a/include/linux/mfd/abx500/ux500_chargalg.h > +++ b/include/linux/mfd/abx500/ux500_chargalg.h > @@ -17,6 +17,7 @@ struct ux500_charger; > > struct ux500_charger_ops { > int (*enable) (struct ux500_charger *, int, int, int); > + int (*check_enable) (struct ux500_charger *, int, int); > int (*kick_wd) (struct ux500_charger *); > int (*update_curr) (struct ux500_charger *, int); > }; > -- > 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/