summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Murthy <arun.murthy@stericsson.com>2011-09-21 11:22:59 +0530
committerSrinidhi KASAGAR <srinidhi.kasagar@stericsson.com>2011-09-22 12:24:15 +0200
commit4bbfac33cc8b4670dd27c7e49002308baf41b787 (patch)
treeb4b5b2b9c2814338329995daaa5fa51fc93ef752
parentdacc378d3827cb270504048e0eab888784ceb3be (diff)
power: ab5500-bm: update usb state change interface to otg notifier
Remove usb_state_changed() exported function. Replace it with otg notifier call. This makes static_di redundant so it is removed. Moreover, there is no need to protect usb_state.usb_changed with usb_lock. So usb_lock is removed as well. Usb state is fabricated based on the reported mA. State is not as accurate as reading it directly from the usb controller. This should not matter as battery- manager driver should care more about mA than the state anyway. Change-Id: I180062a87ca773b5c215aee3ef1c60315d309d42 Signed-off-by: Arun Murthy <arun.murthy@stericsson.com> Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31577 Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--drivers/power/ab5500_charger.c71
-rw-r--r--include/linux/mfd/abx500/ab5500-bm.h4
2 files changed, 53 insertions, 22 deletions
diff --git a/drivers/power/ab5500_charger.c b/drivers/power/ab5500_charger.c
index 8b5b081fe34..b4ac1ac6bb7 100644
--- a/drivers/power/ab5500_charger.c
+++ b/drivers/power/ab5500_charger.c
@@ -27,6 +27,7 @@
#include <linux/mfd/abx500/ab5500-bm.h>
#include <linux/mfd/abx500/ab5500-gpadc.h>
#include <linux/mfd/abx500/ux500_chargalg.h>
+#include <linux/usb/otg.h>
/* Charger constants */
#define NO_PW_CONN 0
@@ -168,6 +169,11 @@ struct ab5500_charger_usb_state {
* Work for checking Main thermal status
* @check_usb_thermal_prot_work:
* Work for checking USB thermal status
+ * @ otg: pointer to struct otg_transceiver, used to
+ * notify the current during a standard host
+ * charger.
+ * @nb: structture of type notifier_block, which has
+ * a function pointer referenced by usb driver.
*/
struct ab5500_charger {
struct device *dev;
@@ -190,15 +196,10 @@ struct ab5500_charger {
struct work_struct usb_link_status_work;
struct work_struct usb_state_changed_work;
struct work_struct check_usb_thermal_prot_work;
+ struct otg_transceiver *otg;
+ struct notifier_block nb;
};
-/*
- * TODO: This variable is static in order to get information
- * about maximum current and USB state from the USB driver
- * This should be solved in a better way
- */
-static struct ab5500_charger *static_di;
-
/* USB properties */
static enum power_supply_property ab5500_charger_usb_props[] = {
POWER_SUPPLY_PROP_HEALTH,
@@ -1130,15 +1131,16 @@ static void ab5500_charger_usb_link_status_work(struct work_struct *work)
static void ab5500_charger_usb_state_changed_work(struct work_struct *work)
{
int ret;
+ unsigned long flags;
struct ab5500_charger *di = container_of(work,
struct ab5500_charger, usb_state_changed_work);
if (!di->vbus_detected)
return;
- spin_lock(&di->usb_state.usb_lock);
+ spin_lock_irqsave(&di->usb_state.usb_lock, flags);
di->usb_state.usb_changed = false;
- spin_unlock(&di->usb_state.usb_lock);
+ spin_unlock_irqrestore(&di->usb_state.usb_lock, flags);
/*
* wait for some time until you get updates from the usb stack
@@ -1521,25 +1523,41 @@ static struct ab5500_charger_interrupts ab5500_charger_irq[] = {
/*{"CHG_SW_TIMER_OUT", ab5500_charger_chwdexp_handler},*/
};
-void ab5500_charger_usb_state_changed(u8 bm_usb_state, u16 mA)
+static int ab5500_charger_usb_notifier_call(struct notifier_block *nb,
+ unsigned long event, void *power)
{
- struct ab5500_charger *di = static_di;
+ struct ab5500_charger *di =
+ container_of(nb, struct ab5500_charger, nb);
+ enum ab5500_usb_state bm_usb_state;
+ unsigned mA = *((unsigned *)power);
+
+ /* TODO: State is fabricate here. See if charger really needs USB
+ * state or if mA is enough
+ */
+ if ((di->usb_state.usb_current == 2) && (mA > 2))
+ bm_usb_state = AB5500_BM_USB_STATE_RESUME;
+ else if (mA == 0)
+ bm_usb_state = AB5500_BM_USB_STATE_RESET_HS;
+ else if (mA == 2)
+ bm_usb_state = AB5500_BM_USB_STATE_SUSPEND;
+ else if (mA >= 8) /* 8, 100, 500 */
+ bm_usb_state = AB5500_BM_USB_STATE_CONFIGURED;
+ else /* Should never occur */
+ bm_usb_state = AB5500_BM_USB_STATE_RESET_FS;
dev_dbg(di->dev, "%s usb_state: 0x%02x mA: %d\n",
__func__, bm_usb_state, mA);
spin_lock(&di->usb_state.usb_lock);
di->usb_state.usb_changed = true;
- spin_unlock(&di->usb_state.usb_lock);
-
di->usb_state.state = bm_usb_state;
di->usb_state.usb_current = mA;
+ spin_unlock(&di->usb_state.usb_lock);
queue_work(di->charger_wq, &di->usb_state_changed_work);
- return;
+ return NOTIFY_OK;
}
-EXPORT_SYMBOL(ab5500_charger_usb_state_changed);
#if defined(CONFIG_PM)
static int ab5500_charger_resume(struct platform_device *pdev)
@@ -1585,6 +1603,9 @@ static int __devexit ab5500_charger_remove(struct platform_device *pdev)
free_irq(irq, di);
}
+ otg_unregister_notifier(di->otg, &di->nb);
+ otg_put_transceiver(di->otg);
+
/* Delete the work queue */
destroy_workqueue(di->charger_wq);
@@ -1606,8 +1627,6 @@ static int __devinit ab5500_charger_probe(struct platform_device *pdev)
if (!di)
return -ENOMEM;
- static_di = di;
-
/* get parent data */
di->dev = &pdev->dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
@@ -1702,6 +1721,18 @@ static int __devinit ab5500_charger_probe(struct platform_device *pdev)
goto free_device_info;
}
+ di->otg = otg_get_transceiver();
+ if (!di->otg) {
+ dev_err(di->dev, "failed to get otg transceiver\n");
+ goto free_usb;
+ }
+ di->nb.notifier_call = ab5500_charger_usb_notifier_call;
+ ret = otg_register_notifier(di->otg, &di->nb);
+ if (ret) {
+ dev_err(di->dev, "failed to register otg notifier\n");
+ goto put_otg_transceiver;
+ }
+
/* Identify the connected charger types during startup */
charger_status = ab5500_charger_detect_chargers(di);
if (charger_status & USB_PW_CONN) {
@@ -1734,13 +1765,17 @@ static int __devinit ab5500_charger_probe(struct platform_device *pdev)
return ret;
free_irq:
- power_supply_unregister(&di->usb_chg.psy);
+ otg_unregister_notifier(di->otg, &di->nb);
/* We also have to free all successfully registered irqs */
for (i = i - 1; i >= 0; i--) {
irq = platform_get_irq_byname(pdev, ab5500_charger_irq[i].name);
free_irq(irq, di);
}
+put_otg_transceiver:
+ otg_put_transceiver(di->otg);
+free_usb:
+ power_supply_unregister(&di->usb_chg.psy);
free_charger_wq:
destroy_workqueue(di->charger_wq);
free_device_info:
diff --git a/include/linux/mfd/abx500/ab5500-bm.h b/include/linux/mfd/abx500/ab5500-bm.h
index f62137a6e9d..cfad11c530c 100644
--- a/include/linux/mfd/abx500/ab5500-bm.h
+++ b/include/linux/mfd/abx500/ab5500-bm.h
@@ -99,13 +99,9 @@
#define BATTERY_UNKNOWN 0
#ifdef CONFIG_AB5500_BM
-void ab5500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
struct ab5500_btemp *ab5500_btemp_get(void);
int ab5500_btemp_get_batctrl_temp(struct ab5500_btemp *btemp);
#else
-static void ab5500_charger_usb_state_changed(u8 bm_usb_state, u16 mA)
-{
-}
static inline struct ab5500_btemp *ab5500_btemp_get(void)
{
return 0;