Skip to content

Commit

Permalink
ab8500-bm: Charge only mode fixes for the ab9540
Browse files Browse the repository at this point in the history
Fix for charging not getting enabled in charge only mode by
external charger.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
  • Loading branch information
Lee Jones committed Mar 7, 2013
1 parent 789ca7b commit 8891716
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 0 deletions.
42 changes: 42 additions & 0 deletions drivers/power/ab8500_charger.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
Expand Down Expand Up @@ -97,6 +98,10 @@
#define AB8500_SW_CONTROL_FALLBACK 0x03
/* Wait for enumeration before charing in us */
#define WAIT_ACA_RID_ENUMERATION (5 * 1000)
/*External charger control*/
#define AB8500_SYS_CHARGER_CONTROL_REG 0x52
#define EXTERNAL_CHARGER_DISABLE_REG_VAL 0x03
#define EXTERNAL_CHARGER_ENABLE_REG_VAL 0x07

/* UsbLineStatus register - usb types */
enum ab8500_charger_link_status {
Expand Down Expand Up @@ -1678,6 +1683,29 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
return ret;
}

static int ab8500_external_charger_prepare(struct notifier_block *charger_nb,
unsigned long event, void *data)
{
int ret;
struct device *dev = data;
/*Toggle External charger control pin*/
ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
AB8500_SYS_CHARGER_CONTROL_REG,
EXTERNAL_CHARGER_DISABLE_REG_VAL);
if (ret < 0) {
dev_err(dev, "write reg failed %d\n", ret);
goto out;
}
ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
AB8500_SYS_CHARGER_CONTROL_REG,
EXTERNAL_CHARGER_ENABLE_REG_VAL);
if (ret < 0)
dev_err(dev, "Write reg failed %d\n", ret);

out:
return ret;
}

/**
* ab8500_charger_usb_check_enable() - enable usb charging
* @charger: pointer to the ux500_charger structure
Expand Down Expand Up @@ -3221,6 +3249,10 @@ static int ab8500_charger_suspend(struct platform_device *pdev,
#define ab8500_charger_resume NULL
#endif

static struct notifier_block charger_nb = {
.notifier_call = ab8500_external_charger_prepare,
};

static int ab8500_charger_remove(struct platform_device *pdev)
{
struct ab8500_charger *di = platform_get_drvdata(pdev);
Expand Down Expand Up @@ -3250,6 +3282,11 @@ static int ab8500_charger_remove(struct platform_device *pdev)
/* Delete the work queue */
destroy_workqueue(di->charger_wq);

/* Unregister external charger enable notifier */
if (!di->ac_chg.enabled)
blocking_notifier_chain_unregister(
&charger_notifier_list, &charger_nb);

flush_scheduled_work();
if (di->usb_chg.enabled)
power_supply_unregister(&di->usb_chg.psy);
Expand Down Expand Up @@ -3331,6 +3368,11 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->ac_chg.enabled = di->bm->ac_enabled;
di->ac_chg.external = false;

/*notifier for external charger enabling*/
if (!di->ac_chg.enabled)
blocking_notifier_chain_register(
&charger_notifier_list, &charger_nb);

/* USB supply */
/* power_supply base class */
di->usb_chg.psy.name = "ab8500_usb";
Expand Down
14 changes: 14 additions & 0 deletions drivers/power/abx500_chargalg.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ux500_chargalg.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/notifier.h>

/* Watchdog kick interval */
#define CHG_WD_INTERVAL (6 * HZ)
Expand Down Expand Up @@ -243,6 +244,9 @@ struct abx500_chargalg {
struct kobject chargalg_kobject;
};

/*External charger prepare notifier*/
BLOCKING_NOTIFIER_HEAD(charger_notifier_list);

/* Main battery properties */
static enum power_supply_property abx500_chargalg_props[] = {
POWER_SUPPLY_PROP_STATUS,
Expand Down Expand Up @@ -503,6 +507,8 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di)
static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
int vset, int iset)
{
static int abx500_chargalg_ex_ac_enable_toggle;

if (!di->ac_chg || !di->ac_chg->ops.enable)
return -ENXIO;

Expand All @@ -515,6 +521,14 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
di->chg_info.ac_iset = iset;
di->chg_info.ac_vset = vset;

/* Enable external charger */
if (enable && di->ac_chg->external &&
!abx500_chargalg_ex_ac_enable_toggle) {
blocking_notifier_call_chain(&charger_notifier_list,
0, di->dev);
abx500_chargalg_ex_ac_enable_toggle++;
}

return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset);
}

Expand Down
7 changes: 7 additions & 0 deletions drivers/power/pm2301_charger.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,13 @@ static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
ret = pm2xxx_charger_detection(pm2, &val);

if ((ret == 0) && val) {
/*
* When boot is due to AC charger plug-in,
* read interrupt registers
*/
pm2xxx_reg_read(pm2, PM2XXX_REG_INT1, &val);
pm2xxx_reg_read(pm2, PM2XXX_REG_INT2, &val);
pm2xxx_reg_read(pm2, PM2XXX_REG_INT4, &val);
pm2->ac.charger_connected = 1;
pm2->ac_conn = true;
power_supply_changed(&pm2->ac_chg.psy);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/mfd/abx500/ux500_chargalg.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ struct ux500_charger {
bool external;
};

extern struct blocking_notifier_head charger_notifier_list;

#endif

0 comments on commit 8891716

Please sign in to comment.