aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Gardsmark <johan.gardsmark@stericsson.com>2011-01-05 15:23:55 +0100
committerJonas ABERG <jonas.aberg@stericsson.com>2011-02-22 15:58:55 +0100
commitc780a508e42fa293e61eeadd9bbc570eac30c611 (patch)
tree74802e411c824104fe5eb4b2adbea87d6ed39922
parentc90bac6ee27f95669afba190089c47e72929a936 (diff)
power: ab8500_bm: Add support for non-ab8500 chargersu8500-android-2.3_v0.19
Adds support to use non-ab8500 chargers in the ab8500 charging algorithm. The charger specific functions are now stored in a "sub class" charger structure with the power_supply as a "base class". ST-Ericsson ID: WP324917 Change-Id: I3c29c6b767209d750498ecd6b8a690d9fb073109 Signed-off-by: Johan Gardsmark <johan.gardsmark@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/16416 Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r--drivers/power/ab8500_chargalg.c91
-rw-r--r--drivers/power/ab8500_charger.c147
-rw-r--r--include/linux/mfd/ab8500/ab8500-bm.h9
-rw-r--r--include/linux/mfd/ab8500/ux500_chargalg.h37
4 files changed, 194 insertions, 90 deletions
diff --git a/drivers/power/ab8500_chargalg.c b/drivers/power/ab8500_chargalg.c
index d44f350aef6..96c20df02b8 100644
--- a/drivers/power/ab8500_chargalg.c
+++ b/drivers/power/ab8500_chargalg.c
@@ -20,6 +20,7 @@
#include <linux/workqueue.h>
#include <linux/kobject.h>
#include <linux/mfd/ab8500.h>
+#include <linux/mfd/ab8500/ux500_chargalg.h>
#include <linux/mfd/ab8500/ab8500-bm.h>
#include <linux/mfd/ab8500/ab8500-gpadc.h>
@@ -138,6 +139,7 @@ struct ab8500_chargalg_events {
bool btemp_lowhigh;
bool main_thermal_prot;
bool usb_thermal_prot;
+ bool main_ovv;
bool vbus_ovv;
bool usbchargernotok;
bool safety_timer_expired;
@@ -185,6 +187,8 @@ struct ab8500_chargalg {
struct ab8500_chargalg_platform_data *pdata;
struct ab8500_bm_data *bat;
struct power_supply chargalg_psy;
+ struct ux500_charger *ac_chg;
+ struct ux500_charger *usb_chg;
struct ab8500_chargalg_events events;
struct workqueue_struct *chargalg_wq;
struct delayed_work chargalg_periodic_work;
@@ -397,10 +401,15 @@ static void ab8500_chargalg_stop_maintenance_timer(struct ab8500_chargalg *di)
*/
static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di)
{
- if (di->bat->charger_ops.kick_watchdog)
- return di->bat->charger_ops.kick_watchdog(di->parent->charger);
- else
- return -ENXIO;
+ /* Check if charger exists and kick watchdog if charging */
+ if (di->ac_chg && di->ac_chg->ops.kick_wd &&
+ di->chg_info.online_chg & AC_CHG)
+ return di->ac_chg->ops.kick_wd(di->ac_chg);
+ else if (di->usb_chg && di->usb_chg->ops.kick_wd &&
+ di->chg_info.online_chg & USB_CHG)
+ return di->usb_chg->ops.kick_wd(di->usb_chg);
+
+ return -ENXIO;
}
/**
@@ -416,11 +425,16 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di)
static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable,
int vset, int iset)
{
- if (di->bat->charger_ops.ac_en)
- return di->bat->charger_ops.ac_en(di->parent->charger,
- enable, vset, iset);
- else
+ if (!di->ac_chg || !di->ac_chg->ops.enable)
return -ENXIO;
+
+ /* Select maximum of what both the charger and the battery supports */
+ if (di->ac_chg->max_out_volt)
+ vset = min(vset, di->ac_chg->max_out_volt);
+ if (di->ac_chg->max_out_curr)
+ iset = min(iset, di->ac_chg->max_out_curr);
+
+ return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset);
}
/**
@@ -436,11 +450,16 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable,
static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable,
int vset, int iset)
{
- if (di->bat->charger_ops.usb_en)
- return di->bat->charger_ops.usb_en(di->parent->charger,
- enable, vset, iset);
- else
+ if (!di->usb_chg || !di->usb_chg->ops.enable)
return -ENXIO;
+
+ /* Select maximum of what both the charger and the battery supports */
+ if (di->usb_chg->max_out_volt)
+ vset = min(vset, di->usb_chg->max_out_volt);
+ if (di->usb_chg->max_out_curr)
+ iset = min(iset, di->usb_chg->max_out_curr);
+
+ return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset);
}
/**
@@ -614,6 +633,14 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
enum power_supply_property prop;
prop = ext->properties[j];
+ /* Initialize chargers if not already done */
+ if (!di->ac_chg &&
+ ext->type == POWER_SUPPLY_TYPE_MAINS)
+ di->ac_chg = psy_to_ux500_charger(ext);
+ else if (!di->usb_chg &&
+ ext->type == POWER_SUPPLY_TYPE_USB)
+ di->usb_chg = psy_to_ux500_charger(ext);
+
switch (prop) {
case POWER_SUPPLY_PROP_PRESENT:
if (!ext->get_property(ext,
@@ -736,6 +763,8 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
true;
di->events.main_thermal_prot =
false;
+ di->events.main_ovv =
+ false;
di->events.ac_wd_expired =
false;
break;
@@ -744,14 +773,28 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
true;
di->events.mainextchnotok =
false;
+ di->events.main_ovv =
+ false;
di->events.main_thermal_prot =
false;
break;
+ case POWER_SUPPLY_HEALTH_COLD:
case POWER_SUPPLY_HEALTH_OVERHEAT:
di->events.main_thermal_prot =
true;
di->events.mainextchnotok =
false;
+ di->events.main_ovv =
+ false;
+ di->events.ac_wd_expired =
+ false;
+ break;
+ case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
+ di->events.main_ovv = true;
+ di->events.mainextchnotok =
+ false;
+ di->events.main_thermal_prot =
+ false;
di->events.ac_wd_expired =
false;
break;
@@ -760,6 +803,8 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
false;
di->events.mainextchnotok =
false;
+ di->events.main_ovv =
+ false;
di->events.ac_wd_expired =
false;
break;
@@ -788,6 +833,7 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
false;
di->events.vbus_ovv = false;
break;
+ case POWER_SUPPLY_HEALTH_COLD:
case POWER_SUPPLY_HEALTH_OVERHEAT:
di->events.usb_thermal_prot =
true;
@@ -1003,9 +1049,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
if (di->charge_state != STATE_CHG_NOT_OK)
ab8500_chargalg_state_to(di, STATE_CHG_NOT_OK_INIT);
}
- /* VBUS or VBAT OVV. */
- else if (di->events.vbus_ovv || di->events.batt_ovv ||
- !di->chg_info.usb_chg_ok || !di->chg_info.ac_chg_ok) {
+ /* VBUS, Main or VBAT OVV. */
+ else if (di->events.vbus_ovv ||
+ di->events.main_ovv ||
+ di->events.batt_ovv ||
+ !di->chg_info.usb_chg_ok ||
+ !di->chg_info.ac_chg_ok) {
if (di->charge_state != STATE_OVV_PROTECT)
ab8500_chargalg_state_to(di, STATE_OVV_PROTECT_INIT);
}
@@ -1112,8 +1161,11 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
/* Intentional fallthrough */
case STATE_OVV_PROTECT:
- if (!di->events.vbus_ovv && !di->events.batt_ovv &&
- di->chg_info.usb_chg_ok && di->chg_info.ac_chg_ok)
+ if (!di->events.vbus_ovv &&
+ !di->events.main_ovv &&
+ !di->events.batt_ovv &&
+ di->chg_info.usb_chg_ok &&
+ di->chg_info.ac_chg_ok)
ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
break;
@@ -1281,12 +1333,15 @@ static void ab8500_chargalg_periodic_work(struct work_struct *work)
*/
static void ab8500_chargalg_wd_work(struct work_struct *work)
{
+ int ret;
struct ab8500_chargalg *di = container_of(work,
struct ab8500_chargalg, chargalg_wd_work.work);
dev_dbg(di->dev, "ab8500_chargalg_wd_work\n");
- ab8500_chargalg_kick_watchdog(di);
+ ret = ab8500_chargalg_kick_watchdog(di);
+ if (ret < 0)
+ dev_err(di->dev, "failed to kick watchdog\n");
queue_delayed_work(di->chargalg_wq,
&di->chargalg_wd_work, CHG_WD_INTERVAL);
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 9332f44500a..87c554e2c15 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -24,6 +24,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500/ab8500-bm.h>
#include <linux/mfd/ab8500/ab8500-gpadc.h>
+#include <linux/mfd/ab8500/ux500_chargalg.h>
/* Charger constants */
#define NO_PW_CONN 0
@@ -97,9 +98,9 @@ enum ab8500_usb_state {
};
#define to_ab8500_charger_usb_device_info(x) container_of((x), \
- struct ab8500_charger, usb_psy);
+ struct ab8500_charger, usb_chg)
#define to_ab8500_charger_ac_device_info(x) container_of((x), \
- struct ab8500_charger, ac_psy);
+ struct ab8500_charger, ac_chg)
/**
* struct ab8500_charger_interrupts - ab8500 interupts
@@ -150,8 +151,8 @@ struct ab8500_charger_usb_state {
* @bat: Pointer to the ab8500_bm platform data
* @flags: Structure for information about events triggered
* @usb_state: Structure for usb stack information
- * @ac_psy: AC charger power supply
- * @usb_psy: USB charger power supply
+ * @ac_chg: AC charger power supply
+ * @usb_chg: USB charger power supply
* @ac: Structure that holds the AC charger properties
* @usb: Structure that holds the USB charger properties
* @charger_wq: Work queue for the IRQs and checking HW state
@@ -181,8 +182,8 @@ struct ab8500_charger {
struct ab8500_bm_data *bat;
struct ab8500_charger_event_flags flags;
struct ab8500_charger_usb_state usb_state;
- struct power_supply ac_psy;
- struct power_supply usb_psy;
+ struct ux500_charger ac_chg;
+ struct ux500_charger usb_chg;
struct ab8500_charger_info ac;
struct ab8500_charger_info usb;
struct workqueue_struct *charger_wq;
@@ -807,13 +808,15 @@ static int ab8500_charger_kick_main_wd(struct ab8500_charger *di)
* Enable/Disable AC/Mains charging and turns on/off the charging led
* respectively.
**/
-static int ab8500_charger_ac_en(struct ab8500_charger *di,
+static int ab8500_charger_ac_en(struct ux500_charger *charger,
int enable, int vset, int iset)
{
int ret;
int volt_index;
int curr_index;
+ struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
+
if (enable) {
/* Check if AC is connected */
if (!di->ac.charger_connected) {
@@ -942,7 +945,7 @@ static int ab8500_charger_ac_en(struct ab8500_charger *di,
di->ac.wd_expired = false;
dev_dbg(di->dev, "%s Disabled AC charging\n", __func__);
}
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
return ret;
@@ -999,13 +1002,15 @@ disable_charger:
* Enable/Disable USB charging and turns on/off the charging led respectively.
* Returns error code in case of failure else 0(on success)
*/
-static int ab8500_charger_usb_en(struct ab8500_charger *di,
+static int ab8500_charger_usb_en(struct ux500_charger *charger,
int enable, int vset, int ich_out)
{
int ret;
int volt_index;
int curr_index;
+ struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
+
if (enable) {
/* Check if USB is connected */
if (!di->usb.charger_connected) {
@@ -1085,7 +1090,7 @@ static int ab8500_charger_usb_en(struct ab8500_charger *di,
di->usb.wd_expired = false;
dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
}
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
return ret;
@@ -1106,9 +1111,17 @@ disable_charger:
* Kick charger watchdog
* Returns error code in case of failure else 0(on success)
*/
-static int ab8500_charger_watchdog_kick(struct ab8500_charger *di)
+static int ab8500_charger_watchdog_kick(struct ux500_charger *charger)
{
int ret;
+ struct ab8500_charger *di;
+
+ if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+ di = to_ab8500_charger_ac_device_info(charger);
+ else if (charger->psy.type == POWER_SUPPLY_TYPE_USB)
+ di = to_ab8500_charger_usb_device_info(charger);
+ else
+ return -ENXIO;
ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
@@ -1118,12 +1131,6 @@ static int ab8500_charger_watchdog_kick(struct ab8500_charger *di)
return ret;
}
-static struct ab8500_charger_ops charger_ops = {
- .ac_en = ab8500_charger_ac_en,
- .usb_en = ab8500_charger_usb_en,
- .kick_watchdog = ab8500_charger_watchdog_kick,
-};
-
/**
* ab8500_charger_check_hw_failure_work() - check main charger failure
* @work: pointer to the work_struct structure
@@ -1148,7 +1155,7 @@ static void ab8500_charger_check_hw_failure_work(struct work_struct *work)
}
if (!(reg_value & MAIN_CH_NOK)) {
di->flags.mainextchnotok = false;
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
}
}
if (di->flags.vbus_ovv) {
@@ -1161,7 +1168,7 @@ static void ab8500_charger_check_hw_failure_work(struct work_struct *work)
}
if (!(reg_value & VBUS_OVV_TH)) {
di->flags.vbus_ovv = false;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
}
/* If we still have a failure, schedule a new check */
@@ -1231,7 +1238,7 @@ static void ab8500_charger_ac_work(struct work_struct *work)
di->ac.charger_connected = 0;
}
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
}
/**
@@ -1259,7 +1266,7 @@ void ab8500_charger_detect_usb_type_work(struct work_struct *work)
if (!(ret & USB_PW_CONN)) {
di->vbus_detected = 0;
di->usb.charger_connected = 0;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
} else {
di->vbus_detected = 1;
@@ -1269,7 +1276,7 @@ void ab8500_charger_detect_usb_type_work(struct work_struct *work)
ret = ab8500_charger_detect_usb_type(di);
if (!ret) {
di->usb.charger_connected = 1;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
break;
@@ -1286,7 +1293,7 @@ void ab8500_charger_detect_usb_type_work(struct work_struct *work)
ret = ab8500_charger_detect_usb_type(di);
if (!ret) {
di->usb.charger_connected = 1;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
}
break;
@@ -1319,7 +1326,7 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
if (!(ret & USB_PW_CONN)) {
di->vbus_detected = 0;
di->usb.charger_connected = 0;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
} else {
di->vbus_detected = 1;
ret = ab8500_charger_read_usb_type(di);
@@ -1333,11 +1340,11 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
return;
}
di->usb.charger_connected = 1;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
} else if (ret == -ENXIO) {
/* No valid charger type detected */
di->usb.charger_connected = 0;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
}
}
@@ -1373,7 +1380,7 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
case AB8500_BM_USB_STATE_SUSPEND:
case AB8500_BM_USB_STATE_MAX:
di->usb.charger_connected = 0;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
break;
case AB8500_BM_USB_STATE_RESUME:
@@ -1398,7 +1405,7 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
return;
}
di->usb.charger_connected = 1;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
break;
@@ -1433,7 +1440,7 @@ static void ab8500_charger_check_usbchargernotok_work(struct work_struct *work)
else
di->flags.usbchargernotok = false;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
/**
@@ -1463,7 +1470,7 @@ static void ab8500_charger_check_main_thermal_prot_work(
else
di->flags.main_thermal_prot = false;
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
}
/**
@@ -1493,7 +1500,7 @@ static void ab8500_charger_check_usb_thermal_prot_work(
else
di->flags.usb_thermal_prot = false;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
/**
@@ -1543,7 +1550,7 @@ static irqreturn_t ab8500_charger_mainextchnotok_handler(int irq, void *_di)
dev_dbg(di->dev, "Main charger not ok\n");
di->flags.mainextchnotok = true;
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
/* Schedule a new HW failure check */
queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0);
@@ -1733,11 +1740,11 @@ static irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di)
*/
if (di->ac.charger_online) {
di->ac.wd_expired = true;
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
}
if (di->usb.charger_online) {
di->usb.wd_expired = true;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
}
return IRQ_HANDLED;
@@ -1756,7 +1763,7 @@ static irqreturn_t ab8500_charger_vbusovv_handler(int irq, void *_di)
dev_dbg(di->dev, "VBUS overvoltage detected\n");
di->flags.vbus_ovv = true;
- power_supply_changed(&di->usb_psy);
+ power_supply_changed(&di->usb_chg.psy);
/* Schedule a new HW failure check */
queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0);
@@ -1784,7 +1791,7 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy,
{
struct ab8500_charger *di;
- di = to_ab8500_charger_ac_device_info(psy);
+ di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy));
switch (psp) {
case POWER_SUPPLY_PROP_HEALTH:
@@ -1841,7 +1848,7 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy,
{
struct ab8500_charger *di;
- di = to_ab8500_charger_usb_device_info(psy);
+ di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy));
switch (psp) {
case POWER_SUPPLY_PROP_HEALTH:
@@ -2080,10 +2087,10 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
int i, irq, ret;
/* Disable AC charging */
- ab8500_charger_ac_en(di, false, 0, 0);
+ ab8500_charger_ac_en(&di->ac_chg, false, 0, 0);
/* Disable USB charging */
- ab8500_charger_usb_en(di, false, 0, 0);
+ ab8500_charger_usb_en(&di->usb_chg, false, 0, 0);
/* Disable interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
@@ -2101,8 +2108,8 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
destroy_workqueue(di->charger_wq);
flush_scheduled_work();
- power_supply_unregister(&di->usb_psy);
- power_supply_unregister(&di->ac_psy);
+ power_supply_unregister(&di->usb_chg.psy);
+ power_supply_unregister(&di->ac_chg.psy);
platform_set_drvdata(pdev, NULL);
kfree(di);
@@ -2147,26 +2154,40 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
}
di->bat = plat->battery;
- /* Set up function pointers to be used by the charging algorithm */
- di->bat->charger_ops = charger_ops;
-
/* AC supply */
- di->ac_psy.name = "ab8500_ac";
- di->ac_psy.type = POWER_SUPPLY_TYPE_MAINS;
- di->ac_psy.properties = ab8500_charger_ac_props;
- di->ac_psy.num_properties = ARRAY_SIZE(ab8500_charger_ac_props);
- di->ac_psy.get_property = ab8500_charger_ac_get_property;
- di->ac_psy.supplied_to = di->pdata->supplied_to;
- di->ac_psy.num_supplicants = di->pdata->num_supplicants;
+ /* power_supply base class */
+ di->ac_chg.psy.name = "ab8500_ac";
+ di->ac_chg.psy.type = POWER_SUPPLY_TYPE_MAINS;
+ di->ac_chg.psy.properties = ab8500_charger_ac_props;
+ di->ac_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_ac_props);
+ di->ac_chg.psy.get_property = ab8500_charger_ac_get_property;
+ di->ac_chg.psy.supplied_to = di->pdata->supplied_to;
+ di->ac_chg.psy.num_supplicants = di->pdata->num_supplicants;
+ /* ux500_charger sub-class */
+ di->ac_chg.ops.enable = &ab8500_charger_ac_en;
+ di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
+ di->ac_chg.max_out_volt = ab8500_charger_voltage_map[
+ ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
+ di->ac_chg.max_out_curr = ab8500_charger_current_map[
+ ARRAY_SIZE(ab8500_charger_current_map) - 1];
/* USB supply */
- di->usb_psy.name = "ab8500_usb";
- di->usb_psy.type = POWER_SUPPLY_TYPE_USB;
- di->usb_psy.properties = ab8500_charger_usb_props;
- di->usb_psy.num_properties = ARRAY_SIZE(ab8500_charger_usb_props);
- di->usb_psy.get_property = ab8500_charger_usb_get_property;
- di->usb_psy.supplied_to = di->pdata->supplied_to;
- di->usb_psy.num_supplicants = di->pdata->num_supplicants;
+ /* power_supply base class */
+ di->usb_chg.psy.name = "ab8500_usb";
+ di->usb_chg.psy.type = POWER_SUPPLY_TYPE_USB;
+ di->usb_chg.psy.properties = ab8500_charger_usb_props;
+ di->usb_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_usb_props);
+ di->usb_chg.psy.get_property = ab8500_charger_usb_get_property;
+ di->usb_chg.psy.supplied_to = di->pdata->supplied_to;
+ di->usb_chg.psy.num_supplicants = di->pdata->num_supplicants;
+ /* ux500_charger sub-class */
+ di->usb_chg.ops.enable = &ab8500_charger_usb_en;
+ di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
+ di->usb_chg.max_out_volt = ab8500_charger_voltage_map[
+ ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
+ di->usb_chg.max_out_curr = ab8500_charger_current_map[
+ ARRAY_SIZE(ab8500_charger_current_map) - 1];
+
/* Create a work queue for the charger */
di->charger_wq =
@@ -2227,14 +2248,14 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
}
/* Register AC charger class */
- ret = power_supply_register(di->dev, &di->ac_psy);
+ ret = power_supply_register(di->dev, &di->ac_chg.psy);
if (ret) {
dev_err(di->dev, "failed to register AC charger\n");
goto free_charger_wq;
}
/* Register USB charger class */
- ret = power_supply_register(di->dev, &di->usb_psy);
+ ret = power_supply_register(di->dev, &di->usb_chg.psy);
if (ret) {
dev_err(di->dev, "failed to register USB charger\n");
goto free_ac;
@@ -2245,7 +2266,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
if (charger_status & AC_PW_CONN) {
di->ac.charger_connected = 1;
di->ac_conn = true;
- power_supply_changed(&di->ac_psy);
+ power_supply_changed(&di->ac_chg.psy);
}
if (charger_status & USB_PW_CONN) {
@@ -2278,7 +2299,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
return ret;
free_irq:
- power_supply_unregister(&di->usb_psy);
+ power_supply_unregister(&di->usb_chg.psy);
/* We also have to free all successfully registered irqs */
for (i = i - 1; i >= 0; i--) {
@@ -2286,7 +2307,7 @@ free_irq:
free_irq(irq, di);
}
free_ac:
- power_supply_unregister(&di->ac_psy);
+ power_supply_unregister(&di->ac_chg.psy);
free_charger_wq:
destroy_workqueue(di->charger_wq);
free_device_info:
diff --git a/include/linux/mfd/ab8500/ab8500-bm.h b/include/linux/mfd/ab8500/ab8500-bm.h
index 82a0c15ffda..d99a150f992 100644
--- a/include/linux/mfd/ab8500/ab8500-bm.h
+++ b/include/linux/mfd/ab8500/ab8500-bm.h
@@ -260,15 +260,8 @@ struct v_to_cap {
};
/* Forward declaration */
-struct ab8500_charger;
struct ab8500_fg;
-struct ab8500_charger_ops {
- int (*ac_en) (struct ab8500_charger *, int, int, int);
- int (*usb_en) (struct ab8500_charger *, int, int, int);
- int (*kick_watchdog) (struct ab8500_charger *);
-};
-
/**
* struct ab8500_fg_parameters - Fuel gauge algorithm parameters, in seconds
* if not specified
@@ -394,7 +387,6 @@ struct ab8500_bm_charger_parameters {
* @cap_levels capacity in percent for the different capacity levels
* @pcb_ntc table with resistance to temp for PCB mounted NTC
* @bat_type table of supported battery types
- * @charger_ops pointers to the charger functions used by the algorithm
* @chg_params charger parameters
* @fg_params fuel gauge parameters
*/
@@ -416,7 +408,6 @@ struct ab8500_bm_data {
struct ab8500_bm_capacity_levels *cap_levels;
struct res_to_temp *pcb_ntc;
struct battery_type *bat_type;
- struct ab8500_charger_ops charger_ops;
const struct ab8500_bm_charger_parameters *chg_params;
const struct ab8500_fg_parameters *fg_params;
};
diff --git a/include/linux/mfd/ab8500/ux500_chargalg.h b/include/linux/mfd/ab8500/ux500_chargalg.h
new file mode 100644
index 00000000000..2048ab65c8f
--- /dev/null
+++ b/include/linux/mfd/ab8500/ux500_chargalg.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Johan Gardsmark <johan.gardsmark@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _UX500_CHARGALG_H
+#define _UX500_CHARGALG_H
+
+#include <linux/power_supply.h>
+
+#define psy_to_ux500_charger(x) container_of((x), \
+ struct ux500_charger, psy)
+
+/* Forward declaration */
+struct ux500_charger;
+
+struct ux500_charger_ops {
+ int (*enable) (struct ux500_charger *, int, int, int);
+ int (*kick_wd) (struct ux500_charger *);
+};
+
+/**
+ * struct ux500_charger - power supply ux500 charger sub class
+ * @psy power supply base class
+ * @ops ux500 charger operations
+ * @max_out_volt maximum output charger voltage in mV
+ * @max_out_curr maximum output charger current in mA
+ */
+struct ux500_charger {
+ struct power_supply psy;
+ struct ux500_charger_ops ops;
+ int max_out_volt;
+ int max_out_curr;
+};
+
+#endif