power: pm8921-charger: support for external charger drivers
Allow the pm8921-charger driver to initiate charging on a
registered 3rd party charging driver through the power supply class.
Also enable the maintenance of charging properties such as online
and charge type using the power supply class rather than
directly depending on the 3rd party driver.
When a external charger is registered using power_supply_register
the external_power_changed callback of the charger driver checks
for an external charger named "dc". This removes the dependency
of a 3rd party charger to call directly into the charger driver.
Also, update the isl9519q driver to reflect the changes and
utilize power supply class calls to enable charging
on the isl chip from PM8921 charger driver.
This serves as an example for other 3rd party external
chargers supporting PMIC with high current charging.
Finally, add pr_fmt macro which automatically adds function name
to print statements and remove __func__ from individual print
statements.
Change-Id: If05e598be260d924ec3263bad33317cf4e7543a1
Signed-off-by: David Keitel <dkeitel@codeaurora.org>
diff --git a/drivers/power/isl9519q.c b/drivers/power/isl9519q.c
index e4729f2..7ebbf46 100644
--- a/drivers/power/isl9519q.c
+++ b/drivers/power/isl9519q.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/i2c.h>
#include <linux/gpio.h>
@@ -20,7 +21,7 @@
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/msm-charger.h>
-#include <linux/mfd/pm8xxx/pm8921-charger.h>
+#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/i2c/isl9519.h>
#include <linux/msm_adc.h>
@@ -54,7 +55,7 @@
struct msm_hardware_charger adapter_hw_chg;
int suspended;
int charge_at_resume;
- struct ext_chg_pm8921 ext_chg;
+ struct power_supply dc_psy;
spinlock_t lock;
bool notify_by_pmic;
bool trickle;
@@ -75,10 +76,11 @@
dev_err(&isl_chg->client->dev,
"i2c read fail: can't read from %02x: %d\n", reg, ret);
return -EAGAIN;
- } else
+ } else {
*val = ret;
+ }
- pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, *val);
+ pr_debug("reg=0x%x.val=0x%x.\n", reg, *val);
return 0;
}
@@ -89,7 +91,7 @@
int ret;
struct isl9519q_struct *isl_chg;
- pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+ pr_debug("reg=0x%x.val=0x%x.\n", reg, val);
isl_chg = i2c_get_clientdata(client);
ret = i2c_smbus_write_word_data(isl_chg->client, reg, val);
@@ -118,44 +120,41 @@
struct adc_chan_result adc_chan_result;
struct completion conv_complete_evt;
- pr_debug("%s: called for %d\n", __func__, channel);
+ pr_debug("called for %d\n", channel);
ret = adc_channel_open(channel, &h);
if (ret) {
- pr_err("%s: couldnt open channel %d ret=%d\n",
- __func__, channel, ret);
+ pr_err("couldnt open channel %d ret=%d\n", channel, ret);
goto out;
}
init_completion(&conv_complete_evt);
ret = adc_channel_request_conv(h, &conv_complete_evt);
if (ret) {
- pr_err("%s: couldnt request conv channel %d ret=%d\n",
- __func__, channel, ret);
+ pr_err("couldnt request conv channel %d ret=%d\n",
+ channel, ret);
goto out;
}
ret = wait_for_completion_interruptible(&conv_complete_evt);
if (ret) {
- pr_err("%s: wait interrupted channel %d ret=%d\n",
- __func__, channel, ret);
+ pr_err("wait interrupted channel %d ret=%d\n", channel, ret);
goto out;
}
ret = adc_channel_read_result(h, &adc_chan_result);
if (ret) {
- pr_err("%s: couldnt read result channel %d ret=%d\n",
- __func__, channel, ret);
+ pr_err("couldnt read result channel %d ret=%d\n",
+ channel, ret);
goto out;
}
ret = adc_channel_close(h);
if (ret)
- pr_err("%s: couldnt close channel %d ret=%d\n",
- __func__, channel, ret);
+ pr_err("couldnt close channel %d ret=%d\n", channel, ret);
if (mv_reading)
*mv_reading = (int)adc_chan_result.measurement;
- pr_debug("%s: done for %d\n", __func__, channel);
+ pr_debug("done for %d\n", channel);
return adc_chan_result.physical;
out:
*mv_reading = 0;
- pr_debug("%s: done with error for %d\n", __func__, channel);
+ pr_debug("done with error for %d\n", channel);
return -EINVAL;
}
@@ -168,7 +167,7 @@
ret = isl9519q_read_reg(isl_chg->client, CONTROL_REG, &ctrl);
if (!ret) {
- pr_debug("%s.control_reg=0x%x.\n", __func__, ctrl);
+ pr_debug("control_reg=0x%x.\n", ctrl);
} else {
dev_err(&isl_chg->client->dev,
"%s couldnt read cntrl reg\n", __func__);
@@ -220,7 +219,7 @@
dev_dbg(&isl_chg->client->dev, "%s\n", __func__);
if (!isl_chg->charging) {
- pr_info("%s.stop charging.\n", __func__);
+ pr_debug("stop charging.\n");
isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG, 0);
return; /* Stop periodic worker */
}
@@ -241,17 +240,15 @@
static int isl9519q_start_charging(struct isl9519q_struct *isl_chg,
int chg_voltage, int chg_current)
{
- int ret = 0;
-
- pr_info("%s.\n", __func__);
+ pr_debug("\n");
if (isl_chg->charging) {
- pr_warn("%s.already charging.\n", __func__);
+ pr_warn("already charging.\n");
return 0;
}
if (isl_chg->suspended) {
- pr_warn("%s.suspended - can't start charging.\n", __func__);
+ pr_warn("suspended - can't start charging.\n");
isl_chg->charge_at_resume = 1;
return 0;
}
@@ -268,15 +265,15 @@
isl_chg->charging = true;
- return ret;
+ return 0;
}
static int isl9519q_stop_charging(struct isl9519q_struct *isl_chg)
{
- pr_info("%s.\n", __func__);
+ pr_debug("\n");
if (!(isl_chg->charging)) {
- pr_warn("%s.already not charging.\n", __func__);
+ pr_warn("already not charging.\n");
return 0;
}
@@ -298,39 +295,6 @@
return 0;
}
-static int isl_ext_start_charging(void *ctx)
-{
- int rc;
- struct isl9519q_struct *isl_chg = ctx;
- unsigned long flags;
-
- spin_lock_irqsave(&isl_chg->lock, flags);
- rc = isl9519q_start_charging(isl_chg, 0, isl_chg->chgcurrent);
- spin_unlock_irqrestore(&isl_chg->lock, flags);
-
- return rc;
-}
-
-static int isl_ext_stop_charging(void *ctx)
-{
- int rc;
- struct isl9519q_struct *isl_chg = ctx;
- unsigned long flags;
-
- spin_lock_irqsave(&isl_chg->lock, flags);
- rc = isl9519q_stop_charging(isl_chg);
- spin_unlock_irqrestore(&isl_chg->lock, flags);
-
- return rc;
-}
-
-static bool isl_ext_is_trickle(void *ctx)
-{
- struct isl9519q_struct *isl_chg = ctx;
-
- return isl_chg->trickle;
-}
-
static int isl_adapter_start_charging(struct msm_hardware_charger *hw_chg,
int chg_voltage, int chg_current)
{
@@ -396,6 +360,114 @@
return IRQ_HANDLED;
}
+static enum power_supply_property pm_power_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+};
+
+static char *pm_power_supplied_to[] = {
+ "battery",
+};
+
+static int get_prop_charge_type(struct isl9519q_struct *isl_chg)
+{
+ if (!isl_chg->present)
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+
+ if (isl_chg->trickle)
+ return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+
+ if (isl_chg->charging)
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+static int pm_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct isl9519q_struct *isl_chg = container_of(psy,
+ struct isl9519q_struct,
+ dc_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = isl_chg->chgcurrent;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = (int)isl_chg->present;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = get_prop_charge_type(isl_chg);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int pm_power_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct isl9519q_struct *isl_chg = container_of(psy,
+ struct isl9519q_struct,
+ dc_psy);
+ unsigned long flags;
+ int rc;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (val->intval) {
+ isl_chg->present = val->intval;
+ } else {
+ isl_chg->present = 0;
+ if (isl_chg->charging)
+ goto stop_charging;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if (val->intval) {
+ if (isl_chg->chgcurrent != val->intval)
+ return -EINVAL;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ if (val->intval && isl_chg->present) {
+ if (val->intval == POWER_SUPPLY_CHARGE_TYPE_FAST)
+ goto start_charging;
+ if (val->intval == POWER_SUPPLY_CHARGE_TYPE_NONE)
+ goto stop_charging;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ power_supply_changed(&isl_chg->dc_psy);
+ return 0;
+
+start_charging:
+ spin_lock_irqsave(&isl_chg->lock, flags);
+ rc = isl9519q_start_charging(isl_chg, 0, isl_chg->chgcurrent);
+ if (rc)
+ pr_err("Failed to start charging rc=%d\n", rc);
+ spin_unlock_irqrestore(&isl_chg->lock, flags);
+ power_supply_changed(&isl_chg->dc_psy);
+ return rc;
+
+stop_charging:
+ spin_lock_irqsave(&isl_chg->lock, flags);
+ rc = isl9519q_stop_charging(isl_chg);
+ if (rc)
+ pr_err("Failed to start charging rc=%d\n", rc);
+ spin_unlock_irqrestore(&isl_chg->lock, flags);
+ power_supply_changed(&isl_chg->dc_psy);
+ return rc;
+}
+
#define MAX_VOLTAGE_REG_MASK 0x3FF0
#define MIN_VOLTAGE_REG_MASK 0x3F00
#define DEFAULT_MAX_VOLTAGE_REG_VALUE 0x1070
@@ -404,8 +476,8 @@
static int __devinit isl9519q_init_adapter(struct isl9519q_struct *isl_chg)
{
int ret;
- struct isl_platform_data *pdata = isl_chg->client->dev.platform_data;
struct i2c_client *client = isl_chg->client;
+ struct isl_platform_data *pdata = client->dev.platform_data;
isl_chg->adapter_hw_chg.type = CHG_TYPE_AC;
isl_chg->adapter_hw_chg.rating = 2;
@@ -473,15 +545,18 @@
{
int ret;
- isl_chg->ext_chg.name = "isl9519q";
- isl_chg->ext_chg.ctx = isl_chg;
- isl_chg->ext_chg.start_charging = isl_ext_start_charging;
- isl_chg->ext_chg.stop_charging = isl_ext_stop_charging;
- isl_chg->ext_chg.is_trickle = isl_ext_is_trickle;
- ret = register_external_dc_charger(&isl_chg->ext_chg);
+ isl_chg->dc_psy.name = "dc";
+ isl_chg->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+ isl_chg->dc_psy.supplied_to = pm_power_supplied_to;
+ isl_chg->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+ isl_chg->dc_psy.properties = pm_power_props;
+ isl_chg->dc_psy.num_properties = ARRAY_SIZE(pm_power_props);
+ isl_chg->dc_psy.get_property = pm_power_get_property;
+ isl_chg->dc_psy.set_property = pm_power_set_property;
+
+ ret = power_supply_register(&isl_chg->client->dev, &isl_chg->dc_psy);
if (ret) {
- pr_err("%s.failed to register external dc charger.ret=%d.\n",
- __func__, ret);
+ pr_err("failed to register dc charger.ret=%d.\n", ret);
return ret;
}
@@ -553,6 +628,36 @@
debugfs_remove_recursive(isl_chg->dent);
}
+static int __devinit isl9519q_hwinit(struct isl9519q_struct *isl_chg)
+{
+ int ret;
+
+ ret = isl9519q_write_reg(isl_chg->client, MAX_SYS_VOLTAGE_REG,
+ isl_chg->max_system_voltage);
+ if (ret) {
+ pr_err("Failed to set MAX_SYS_VOLTAGE rc=%d\n", ret);
+ return ret;
+ }
+
+ ret = isl9519q_write_reg(isl_chg->client, MIN_SYS_VOLTAGE_REG,
+ isl_chg->min_system_voltage);
+ if (ret) {
+ pr_err("Failed to set MIN_SYS_VOLTAGE rc=%d\n", ret);
+ return ret;
+ }
+
+ if (isl_chg->input_current) {
+ ret = isl9519q_write_reg(isl_chg->client,
+ INPUT_CURRENT_REG,
+ isl_chg->input_current);
+ if (ret) {
+ pr_err("Failed to set INPUT_CURRENT rc=%d\n", ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
static int __devinit isl9519q_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -563,7 +668,7 @@
ret = 0;
pdata = client->dev.platform_data;
- pr_info("%s.\n", __func__);
+ pr_debug("\n");
if (pdata == NULL) {
dev_err(&client->dev, "%s no platform data\n", __func__);
@@ -623,24 +728,10 @@
if (isl_chg->min_system_voltage == 0)
isl_chg->min_system_voltage = DEFAULT_MIN_VOLTAGE_REG_VALUE;
- ret = isl9519q_write_reg(isl_chg->client, MAX_SYS_VOLTAGE_REG,
- isl_chg->max_system_voltage);
+ ret = isl9519q_hwinit(isl_chg);
if (ret)
goto free_isl_chg;
- ret = isl9519q_write_reg(isl_chg->client, MIN_SYS_VOLTAGE_REG,
- isl_chg->min_system_voltage);
- if (ret)
- goto free_isl_chg;
-
- if (isl_chg->input_current) {
- ret = isl9519q_write_reg(isl_chg->client,
- INPUT_CURRENT_REG,
- isl_chg->input_current);
- if (ret)
- goto free_isl_chg;
- }
-
if (isl_chg->notify_by_pmic)
ret = isl9519q_init_ext_chg(isl_chg);
else
@@ -652,7 +743,7 @@
the_isl_chg = isl_chg;
create_debugfs_entries(isl_chg);
- pr_info("%s OK.\n", __func__);
+ pr_info("OK.\n");
return 0;
@@ -671,8 +762,13 @@
gpio_free(pdata->valid_n_gpio);
free_irq(client->irq, client);
cancel_delayed_work_sync(&isl_chg->charge_work);
- msm_charger_notify_event(&isl_chg->adapter_hw_chg, CHG_REMOVED_EVENT);
- msm_charger_unregister(&isl_chg->adapter_hw_chg);
+ if (isl_chg->notify_by_pmic) {
+ power_supply_unregister(&isl_chg->dc_psy);
+ } else {
+ msm_charger_notify_event(&isl_chg->adapter_hw_chg,
+ CHG_REMOVED_EVENT);
+ msm_charger_unregister(&isl_chg->adapter_hw_chg);
+ }
remove_debugfs_entries(isl_chg);
the_isl_chg = NULL;
kfree(isl_chg);
@@ -736,8 +832,6 @@
static int __init isl9519q_init(void)
{
- pr_info("%s. isl9519q SW rev 1.01\n", __func__);
-
return i2c_add_driver(&isl9519q_driver);
}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 77e7b89..22d53e9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -235,11 +235,10 @@
unsigned int batt_temp_channel;
unsigned int batt_id_channel;
struct power_supply usb_psy;
- struct power_supply dc_psy;
+ struct power_supply *ext_psy;
struct power_supply batt_psy;
struct dentry *dent;
struct bms_notify bms_notify;
- struct ext_chg_pm8921 *ext;
bool keep_btm_on_suspend;
bool ext_charging;
bool ext_charge_done;
@@ -843,21 +842,29 @@
static bool is_ext_charging(struct pm8921_chg_chip *chip)
{
- if (chip->ext == NULL)
- return false;
+ union power_supply_propval ret = {0,};
- if (chip->ext_charging)
- return true;
+ if (!chip->ext_psy)
+ return false;
+ if (chip->ext_psy->get_property(chip->ext_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
+ return false;
+ if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
+ return ret.intval;
return false;
}
static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
{
- if (chip->ext == NULL)
- return false;
+ union power_supply_propval ret = {0,};
- if (chip->ext->is_trickle(chip->ext->ctx))
+ if (!chip->ext_psy)
+ return false;
+ if (chip->ext_psy->get_property(chip->ext_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
+ return false;
+ if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
return true;
return false;
@@ -922,11 +929,6 @@
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
- if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
- chip = container_of(psy, struct pm8921_chg_chip,
- dc_psy);
- val->intval = is_dc_chg_plugged_in(chip);
- }
if (psy->type == POWER_SUPPLY_TYPE_USB ||
psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
@@ -1082,7 +1084,7 @@
int fsm_state = pm_chg_get_fsm_state(chip);
int i;
- if (chip->ext) {
+ if (chip->ext_psy) {
if (chip->ext_charge_done)
return POWER_SUPPLY_STATUS_FULL;
if (chip->ext_charging)
@@ -1532,7 +1534,7 @@
static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
{
- if (chip->ext == NULL) {
+ if (!chip->ext_psy) {
pr_debug("external charger not registered.\n");
return;
}
@@ -1542,9 +1544,12 @@
return;
}
- chip->ext->stop_charging(chip->ext->ctx);
+ power_supply_set_charge_type(chip->ext_psy,
+ POWER_SUPPLY_CHARGE_TYPE_NONE);
+ pm8921_disable_source_current(false); /* release BATFET */
chip->ext_charging = false;
chip->ext_charge_done = false;
+ bms_notify_check(chip);
}
static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
@@ -1553,11 +1558,10 @@
int batt_present;
int batt_temp_ok;
int vbat_ov;
- int batfet;
unsigned long delay =
round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
- if (chip->ext == NULL) {
+ if (!chip->ext_psy) {
pr_debug("external charger not registered.\n");
return;
}
@@ -1567,11 +1571,9 @@
return;
}
- dc_present = is_dc_chg_plugged_in(chip);
+ dc_present = is_dc_chg_plugged_in(the_chip);
batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
- vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
- batfet = pm_chg_get_rt_status(chip, BATFET_IRQ);
if (!dc_present) {
pr_warn("%s. dc not present.\n", __func__);
@@ -1585,36 +1587,23 @@
pr_warn("%s. battery temperature not ok.\n", __func__);
return;
}
+ pm8921_disable_source_current(true); /* Force BATFET=ON */
+ vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
if (vbat_ov) {
pr_warn("%s. battery over voltage.\n", __func__);
return;
}
- if (!batfet) {
- pr_warn("%s. battery FET not closed.\n", __func__);
- return;
- }
- chip->ext->start_charging(chip->ext->ctx);
+ power_supply_set_charge_type(chip->ext_psy,
+ POWER_SUPPLY_CHARGE_TYPE_FAST);
chip->ext_charging = true;
chip->ext_charge_done = false;
+ bms_notify_check(chip);
/* Start BMS */
schedule_delayed_work(&chip->eoc_work, delay);
wake_lock(&chip->eoc_wake_lock);
}
-static void handle_dc_removal_insertion(struct pm8921_chg_chip *chip)
-{
- int dc_present;
-
- dc_present = is_dc_chg_plugged_in(chip);
- if (chip->dc_present ^ dc_present) {
- chip->dc_present = dc_present;
- power_supply_changed(&chip->dc_psy);
- power_supply_changed(&chip->batt_psy);
- }
- bms_notify_check(chip);
-}
-
#define WRITE_BANK_4 0xC0
static void unplug_wrkarnd_restore_worker(struct work_struct *work)
{
@@ -1687,7 +1676,6 @@
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
@@ -1739,7 +1727,6 @@
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
bms_notify_check(chip);
@@ -1762,7 +1749,6 @@
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
@@ -1773,7 +1759,6 @@
pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
bms_notify_check(chip);
@@ -1902,7 +1887,7 @@
pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
+ handle_stop_ext_chg(chip);
return IRQ_HANDLED;
}
@@ -1915,7 +1900,6 @@
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
@@ -1926,7 +1910,6 @@
pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
/*
@@ -1957,7 +1940,6 @@
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
bms_notify_check(chip);
return IRQ_HANDLED;
}
@@ -1998,11 +1980,16 @@
static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
{
struct pm8921_chg_chip *chip = data;
+ int dc_present;
- pm8921_disable_source_current(true); /* Force BATFET=ON */
-
- handle_dc_removal_insertion(chip);
- handle_start_ext_chg(chip);
+ dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
+ if (chip->ext_psy)
+ power_supply_set_online(chip->ext_psy, dc_present);
+ chip->dc_present = dc_present;
+ if (dc_present)
+ handle_start_ext_chg(chip);
+ else
+ handle_stop_ext_chg(chip);
return IRQ_HANDLED;
}
@@ -2010,9 +1997,6 @@
{
struct pm8921_chg_chip *chip = data;
- pm8921_disable_source_current(false); /* release BATFET */
-
- handle_dc_removal_insertion(chip);
handle_stop_ext_chg(chip);
return IRQ_HANDLED;
}
@@ -2021,12 +2005,41 @@
{
struct pm8921_chg_chip *chip = data;
- pm8921_disable_source_current(false); /* release BATFET */
handle_stop_ext_chg(chip);
return IRQ_HANDLED;
}
+static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
+{
+ struct power_supply *psy = &the_chip->batt_psy;
+ struct power_supply *epsy = dev_get_drvdata(dev);
+ int i, dcin_irq;
+
+ /* Only search for external supply if none is registered */
+ if (!the_chip->ext_psy) {
+ dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
+ for (i = 0; i < epsy->num_supplicants; i++) {
+ if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
+ if (!strncmp(epsy->name, "dc", 2)) {
+ the_chip->ext_psy = epsy;
+ dcin_valid_irq_handler(dcin_irq,
+ the_chip);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void pm_batt_external_power_changed(struct power_supply *psy)
+{
+ /* Only look for an external supply if it hasn't been registered */
+ if (!the_chip->ext_psy)
+ class_for_each_device(power_supply_class, NULL, psy,
+ __pm_batt_external_power_changed_work);
+}
+
/**
* update_heartbeat - internal function to update userspace
* per update_time minutes
@@ -2303,36 +2316,6 @@
return rc;
}
-int register_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
- if (the_chip == NULL) {
- pr_err("called too early\n");
- return -EINVAL;
- }
- /* TODO check function pointers */
- the_chip->ext = ext;
- the_chip->ext_charging = false;
-
- if (is_dc_chg_plugged_in(the_chip))
- pm8921_disable_source_current(true); /* Force BATFET=ON */
-
- handle_start_ext_chg(the_chip);
-
- return 0;
-}
-EXPORT_SYMBOL(register_external_dc_charger);
-
-void unregister_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
- if (the_chip == NULL) {
- pr_err("called too early\n");
- return;
- }
- handle_stop_ext_chg(the_chip);
- the_chip->ext = NULL;
-}
-EXPORT_SYMBOL(unregister_external_dc_charger);
-
/**
* set_disable_status_param -
*
@@ -2411,7 +2394,7 @@
}
}
-/* determines the initial present states and notifies msm_charger */
+/* determines the initial present states */
static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
{
unsigned long flags;
@@ -3041,36 +3024,22 @@
chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
chip->usb_psy.get_property = pm_power_get_property,
- chip->dc_psy.name = "ac",
- 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,
- chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
- chip->dc_psy.get_property = pm_power_get_property,
-
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);
goto free_chip;
}
- rc = power_supply_register(chip->dev, &chip->dc_psy);
- if (rc < 0) {
- pr_err("power_supply_register dc failed rc = %d\n", rc);
- goto unregister_usb;
- }
-
rc = power_supply_register(chip->dev, &chip->batt_psy);
if (rc < 0) {
pr_err("power_supply_register batt failed rc = %d\n", rc);
- goto unregister_dc;
+ goto unregister_usb;
}
platform_set_drvdata(pdev, chip);
@@ -3128,8 +3097,6 @@
free_irqs(chip);
unregister_batt:
power_supply_unregister(&chip->batt_psy);
-unregister_dc:
- power_supply_unregister(&chip->dc_psy);
unregister_usb:
power_supply_unregister(&chip->usb_psy);
free_chip:
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 3e574ff..a954364 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -137,26 +137,6 @@
PM8921_CHG_SRC_DC,
};
-/**
- * struct ext_chg_pm8921 -
- * @name: name of the external charger
- * @ctx: client context.
- * @start_charging: callback to start charging. Can be called from an
- * interrupt context
- * @stop_charging: callback to stop charging. Can be called from an
- * interrupt context
- * @is_trickle: callback to check if trickle charging.
- * Can be called from an interrupt context
- *
- */
-struct ext_chg_pm8921 {
- const char *name;
- void *ctx;
- int (*start_charging) (void *ctx);
- int (*stop_charging) (void *ctx);
- bool (*is_trickle) (void *ctx);
-};
-
#if defined(CONFIG_PM8921_CHARGER) || defined(CONFIG_PM8921_CHARGER_MODULE)
void pm8921_charger_vbus_draw(unsigned int mA);
int pm8921_charger_register_vbus_sn(void (*callback)(int));
@@ -253,28 +233,6 @@
*/
int pm8921_batt_temperature(void);
/**
- * register_external_dc_charger -
- * @ext: The structure representing an external charger
- *
- * RETURNS: Negative error code is there was a problem. Zero for sucess
- *
- * The charger callbacks might be called even before this function
- * completes. The external charger driver should be ready to handle
- * it.
- */
-int register_external_dc_charger(struct ext_chg_pm8921 *ext);
-
-/**
- * unregister_external_dc_charger -
- * @ext: The structure representing an external charger
- *
- * The charger callbacks might be called even before this function
- * completes. The external charger driver should be ready to handle
- * it.
- */
-void unregister_external_dc_charger(struct ext_chg_pm8921 *ext);
-
-/**
* pm8921_usb_ovp_set_threshold -
* Set the usb threshold as defined in by
* enum usb_ov_threshold
@@ -355,15 +313,6 @@
{
return -ENXIO;
}
-static inline int register_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
- pr_err("%s.not implemented.\n", __func__);
- return -ENODEV;
-}
-static inline void unregister_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
- pr_err("%s.not implemented.\n", __func__);
-}
static inline int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
{
return -ENXIO;