linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: mathieu.poirier@linaro.org
To: linux-kernel@vger.kernel.org, cbou@mail.ru, dwmw2@infradead.org
Cc: mathieu.poirier@linaro.org
Subject: [PATCH 52/57] power: abx500_chargalg: Use hrtimer
Date: Tue, 25 Sep 2012 10:12:49 -0600	[thread overview]
Message-ID: <1348589574-25655-53-git-send-email-mathieu.poirier@linaro.org> (raw)
In-Reply-To: <1348589574-25655-1-git-send-email-mathieu.poirier@linaro.org>

From: Hakan Berg <hakan.berg@stericsson.com>

Timers used for charging safety and maintenance must work even when
CPU is power collapsed. By using hrtimers with realtime clock, system
is able to trigger an alarm that wakes the CPU up and make it possible
to handle the event.

Allow a little slack of 5 minutes to the hrtimers to allow CPU to be
waked up in a more optimal power saving way. A 5 minute delay to
time out timers on hours does not impact on safety.

Signed-off-by: Hakan Berg <hakan.berg@stericsson.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Mian Yousaf KAUKAB <mian.yousaf.kaukab@stericsson.com>
---
 drivers/power/abx500_chargalg.c |   94 ++++++++++++++++++++++-----------------
 1 files changed, 53 insertions(+), 41 deletions(-)

diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 636d970..c8849af 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) ST-Ericsson SA 2012
+ * Copyright (c) 2012 Sony Mobile Communications AB
  *
  * Charging algorithm driver for abx500 variants
  *
@@ -8,11 +9,13 @@
  *	Johan Palsson <johan.palsson@stericsson.com>
  *	Karl Komierowski <karl.komierowski@stericsson.com>
  *	Arun R Murthy <arun.murthy@stericsson.com>
+ *	Imre Sunyi <imre.sunyi@sonymobile.com>
  */
 
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/hrtimer.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -32,6 +35,12 @@
 /* End-of-charge criteria counter */
 #define EOC_COND_CNT			10
 
+/* One hour expressed in seconds */
+#define ONE_HOUR_IN_SECONDS		3600
+
+/* Five minutes expressed in seconds */
+#define FIVE_MINUTES_IN_SECONDS		300
+
 #define to_abx500_chargalg_device_info(x) container_of((x), \
 	struct abx500_chargalg, chargalg_psy);
 
@@ -245,8 +254,8 @@ struct abx500_chargalg {
 	struct delayed_work chargalg_periodic_work;
 	struct delayed_work chargalg_wd_work;
 	struct work_struct chargalg_work;
-	struct timer_list safety_timer;
-	struct timer_list maintenance_timer;
+	struct hrtimer safety_timer;
+	struct hrtimer maintenance_timer;
 	struct kobject chargalg_kobject;
 };
 
@@ -261,38 +270,47 @@ BLOCKING_NOTIFIER_HEAD(charger_notifier_list);
 
 /**
  * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
- * @data:	pointer to the abx500_chargalg structure
+ * @timer:	pointer to the hrtimer structure
  *
  * This function gets called when the safety timer for the charger
  * expires
  */
-static void abx500_chargalg_safety_timer_expired(unsigned long data)
+static enum hrtimer_restart
+abx500_chargalg_safety_timer_expired(struct hrtimer *timer)
 {
-	struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+	struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
+							safety_timer);
 	dev_err(di->dev, "Safety timer expired\n");
 	di->events.safety_timer_expired = true;
 
 	/* Trigger execution of the algorithm instantly */
 	queue_work(di->chargalg_wq, &di->chargalg_work);
+
+	return HRTIMER_NORESTART;
 }
 
 /**
  * abx500_chargalg_maintenance_timer_expired() - Expiration of
  * the maintenance timer
- * @i:		pointer to the abx500_chargalg structure
+ * @timer:	pointer to the timer structure
  *
  * This function gets called when the maintenence timer
  * expires
  */
-static void abx500_chargalg_maintenance_timer_expired(unsigned long data)
+static enum hrtimer_restart
+abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer)
+
 {
 
-	struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+	struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
+							maintenance_timer);
 	dev_dbg(di->dev, "Maintenance timer expired\n");
 	di->events.maintenance_timer_expired = true;
 
 	/* Trigger execution of the algorithm instantly */
 	queue_work(di->chargalg_wq, &di->chargalg_work);
+
+	return HRTIMER_NORESTART;
 }
 
 /**
@@ -392,19 +410,16 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
  */
 static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
 {
-	unsigned long timer_expiration = 0;
+	/* Charger-dependent expiration time in hours*/
+	int timer_expiration = 0;
 
 	switch (di->chg_info.charger_type) {
 	case AC_CHG:
-		timer_expiration =
-		round_jiffies(jiffies +
-			(di->bat->main_safety_tmr_h * 3600 * HZ));
+		timer_expiration = di->bat->main_safety_tmr_h;
 		break;
 
 	case USB_CHG:
-		timer_expiration =
-		round_jiffies(jiffies +
-			(di->bat->usb_safety_tmr_h * 3600 * HZ));
+		timer_expiration = di->bat->usb_safety_tmr_h;
 		break;
 
 	default:
@@ -413,11 +428,10 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
 	}
 
 	di->events.safety_timer_expired = false;
-	di->safety_timer.expires = timer_expiration;
-	if (!timer_pending(&di->safety_timer))
-		add_timer(&di->safety_timer);
-	else
-		mod_timer(&di->safety_timer, timer_expiration);
+	hrtimer_set_expires_range(&di->safety_timer,
+		ktime_set(timer_expiration * ONE_HOUR_IN_SECONDS, 0),
+		ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
+	hrtimer_start_expires(&di->safety_timer, HRTIMER_MODE_REL);
 }
 
 /**
@@ -428,8 +442,8 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
  */
 static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
 {
-	di->events.safety_timer_expired = false;
-	del_timer(&di->safety_timer);
+	if (hrtimer_try_to_cancel(&di->safety_timer) >= 0)
+		di->events.safety_timer_expired = false;
 }
 
 /**
@@ -444,17 +458,11 @@ static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
 static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
 	int duration)
 {
-	unsigned long timer_expiration;
-
-	/* Convert from hours to jiffies */
-	timer_expiration = round_jiffies(jiffies + (duration * 3600 * HZ));
-
+	hrtimer_set_expires_range(&di->maintenance_timer,
+		ktime_set(duration * ONE_HOUR_IN_SECONDS, 0),
+		ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
 	di->events.maintenance_timer_expired = false;
-	di->maintenance_timer.expires = timer_expiration;
-	if (!timer_pending(&di->maintenance_timer))
-		add_timer(&di->maintenance_timer);
-	else
-		mod_timer(&di->maintenance_timer, timer_expiration);
+	hrtimer_start_expires(&di->maintenance_timer, HRTIMER_MODE_REL);
 }
 
 /**
@@ -466,8 +474,8 @@ static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
  */
 static void abx500_chargalg_stop_maintenance_timer(struct abx500_chargalg *di)
 {
-	di->events.maintenance_timer_expired = false;
-	del_timer(&di->maintenance_timer);
+	if (hrtimer_try_to_cancel(&di->maintenance_timer) >= 0)
+		di->events.maintenance_timer_expired = false;
 }
 
 /**
@@ -910,11 +918,11 @@ static void abx500_chargalg_check_safety_timer(struct abx500_chargalg *di)
 	 * and charging will be stopped to protect the battery.
 	 */
 	if (di->batt_data.percent == 100 &&
-		!timer_pending(&di->safety_timer)) {
+		!hrtimer_active(&di->safety_timer)) {
 		abx500_chargalg_start_safety_timer(di);
 		dev_dbg(di->dev, "start safety timer\n");
 	} else if (di->batt_data.percent != 100 &&
-		timer_pending(&di->safety_timer)) {
+		hrtimer_active(&di->safety_timer)) {
 		abx500_chargalg_stop_safety_timer(di);
 		dev_dbg(di->dev, "stop safety timer\n");
 	}
@@ -1932,10 +1940,16 @@ static int __devexit abx500_chargalg_remove(struct platform_device *pdev)
 	/* sysfs interface to enable/disbale charging from user space */
 	abx500_chargalg_sysfs_exit(di);
 
+	hrtimer_cancel(&di->safety_timer);
+	hrtimer_cancel(&di->maintenance_timer);
+
+	cancel_delayed_work_sync(&di->chargalg_periodic_work);
+	cancel_delayed_work_sync(&di->chargalg_wd_work);
+	cancel_work_sync(&di->chargalg_work);
+
 	/* Delete the work queue */
 	destroy_workqueue(di->chargalg_wq);
 
-	flush_scheduled_work();
 	power_supply_unregister(&di->chargalg_psy);
 	platform_set_drvdata(pdev, NULL);
 	kfree(di);
@@ -1987,15 +2001,13 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 		abx500_chargalg_external_power_changed;
 
 	/* Initilialize safety timer */
-	init_timer(&di->safety_timer);
+	hrtimer_init(&di->safety_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 	di->safety_timer.function = abx500_chargalg_safety_timer_expired;
-	di->safety_timer.data = (unsigned long) di;
 
 	/* Initilialize maintenance timer */
-	init_timer(&di->maintenance_timer);
+	hrtimer_init(&di->maintenance_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 	di->maintenance_timer.function =
 		abx500_chargalg_maintenance_timer_expired;
-	di->maintenance_timer.data = (unsigned long) di;
 
 	/* Create a work queue for the chargalg */
 	di->chargalg_wq =
-- 
1.7.5.4


  parent reply	other threads:[~2012-09-25 16:14 UTC|newest]

Thread overview: 108+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-25 16:11 [PATCH 00/57] power: Upgrade to ux500 battery management driver mathieu.poirier
2012-09-25 16:11 ` [PATCH 01/57] power: ab8500_bm: Charger current step-up/down mathieu.poirier
2012-09-28  3:41   ` Anton Vorontsov
2012-09-25 16:11 ` [PATCH 02/57] power: ab8500_bm: Don't clear the CCMuxOffset bit mathieu.poirier
2012-09-28  3:42   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 03/57] power: ab8500_btemp: Detect battery type in workqueue mathieu.poirier
2012-09-25 16:12 ` [PATCH 04/57] power: ab8500: bm: movimg back to ab8500 platform data managment mathieu.poirier
2012-09-27  2:42   ` Anton Vorontsov
2012-09-27  2:53   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 05/57] power: ab8500_bm: Rename the power_loss function mathieu.poirier
2012-09-25 16:12 ` [PATCH 06/57] power: ab8500_bm: Skip first CCEOC irq for instant current mathieu.poirier
2012-09-25 16:12 ` [PATCH 07/57] power: ab8500_bm: Detect removed charger mathieu.poirier
2012-09-27  3:09   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 08/57] power: ab8500_fg: flush sync on suspend mathieu.poirier
2012-09-27  3:11   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 09/57] power: ab8500_fg: usleep_range instead of short msleep mathieu.poirier
2012-09-27  2:36   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 10/57] power: ab8500_charger: Handle gpadc errors mathieu.poirier
2012-09-25 16:12 ` [PATCH 11/57] power: Recharge condition not optimal for battery mathieu.poirier
2012-09-27  3:29   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 12/57] power: ab8500_fg: balance IRQ enable mathieu.poirier
2012-09-25 16:12 ` [PATCH 13/57] power: ab8500_bm: Ignore false btemp low interrupt mathieu.poirier
2012-09-27  3:32   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 14/57] power: Adds support for Car/Travel Adapters mathieu.poirier
2012-09-25 16:12 ` [PATCH 15/57] power: ab8500_fg: Round capacity output mathieu.poirier
2012-09-25 16:12 ` [PATCH 16/57] power: bm remove superfluous BTEMP thermal comp mathieu.poirier
2012-09-25 16:12 ` [PATCH 17/57] power: ab8500_bm: Added support for BATT_OVV mathieu.poirier
2012-09-27  3:36   ` Anton Vorontsov
2012-09-28 18:24     ` Mathieu Poirier
2012-09-28 18:26       ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 18/57] power: Add sysfs interfaces for capacity mathieu.poirier
2012-09-27  7:08   ` Anton Vorontsov
2012-09-28 18:26     ` Mathieu Poirier
2012-09-28 19:11       ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 19/57] power: remove unused defines mathieu.poirier
2012-09-25 16:12 ` [PATCH 20/57] power: Adds support for legacy USB chargers mathieu.poirier
2012-09-27  7:15   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 21/57] power: Overflow in current calculation mathieu.poirier
2012-09-25 16:12 ` [PATCH 22/57] power: AB workaround for invalid charger mathieu.poirier
2012-09-25 16:12 ` [PATCH 23/57] power: Add plaform data charger configurables mathieu.poirier
2012-09-25 16:12 ` [PATCH 24/57] power: ab8500_fg: Adjust for RF bursts voltage drops mathieu.poirier
2012-09-25 16:12 ` [PATCH 25/57] power: ab8500: adaptation to ab version mathieu.poirier
2012-09-25 16:12 ` [PATCH 26/57] power: charge: update watchdog for pm2xxx support mathieu.poirier
2012-09-25 16:12 ` [PATCH 27/57] power: sysfs interface update mathieu.poirier
2012-09-27  7:20   ` Anton Vorontsov
2012-09-28 18:26     ` Mathieu Poirier
2012-09-25 16:12 ` [PATCH 28/57] power: ab8500 - Accessing Autopower register fails mathieu.poirier
2012-09-25 16:12 ` [PATCH 29/57] power: ab8500_fg: Goto INIT_RECOVERY when charger removed mathieu.poirier
2012-09-25 16:12 ` [PATCH 30/57] power: ab8500: Flush & sync all works mathieu.poirier
2012-09-27  7:23   ` Anton Vorontsov
2012-09-28 18:28     ` Mathieu Poirier
2012-09-28 19:54       ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 31/57] power: ab8500_fg: fix to use correct battery charge full design mathieu.poirier
2012-09-27  7:27   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 32/57] power: ab8500_charger: Do not touch VBUSOVV bits mathieu.poirier
2012-09-25 16:12 ` [PATCH 33/57] power: u8500_charger: Delay for USB enumeration mathieu.poirier
2012-09-27  7:42   ` Anton Vorontsov
2012-09-28 16:56     ` Mathieu Poirier
2012-09-28 17:09       ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 34/57] power: ab8500_fg: add power cut feature for ab8505 mathieu.poirier
2012-09-28  0:01   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 35/57] power: ab8500_fg: Report unscaled capacity mathieu.poirier
2012-09-25 16:12 ` [PATCH 36/57] power: add backup battery charge voltages mathieu.poirier
2012-09-25 16:12 ` [PATCH 37/57] power: ab8500_bm: Quick re-attach charging behaviour mathieu.poirier
2012-09-28  0:13   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 38/57] power: l9540: Charge only mode fixes mathieu.poirier
2012-09-28  0:27   ` Anton Vorontsov
2012-09-28 18:32     ` Mathieu Poirier
2012-09-25 16:12 ` [PATCH 39/57] power: ab8500_charger: Prevent auto drop of VBUS mathieu.poirier
2012-09-28  0:52   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 40/57] power: ab8500: ADC for battery thermistor mathieu.poirier
2012-09-28  0:57   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 41/57] power: ab8500_btemp: Filter btemp readings mathieu.poirier
2012-09-25 16:12 ` [PATCH 42/57] power: charging: Allow capacity to raise from 1% mathieu.poirier
2012-09-25 16:12 ` [PATCH 43/57] power: charging: Add AB8505_USB_LINK_STATUS mathieu.poirier
2012-09-25 16:12 ` [PATCH 44/57] power: ab8500: remove unecesary define flag mathieu.poirier
2012-09-28  1:05   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 45/57] power: ab8500: defer btemp filtering while init mathieu.poirier
2012-09-28  1:08   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 46/57] power: chargealg: Realign with upstream version mathieu.poirier
2012-09-28  1:17   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 47/57] power: Harmonising platform data declaration/handling mathieu.poirier
2012-09-28  1:11   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 48/57] power: ab8500 : quick re-attach for ext charger mathieu.poirier
2012-09-28  1:19   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 49/57] power: Cancelling status charging notification mathieu.poirier
2012-09-28  2:16   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 50/57] power: ab8500-chargalg: update battery health on safety timer exp mathieu.poirier
2012-09-28  2:21   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 51/57] power: ab8500: Re-alignment with internal developement mathieu.poirier
2012-09-28  2:35   ` Anton Vorontsov
2012-09-28  2:45     ` Anton Vorontsov
2012-09-25 16:12 ` mathieu.poirier [this message]
2012-09-28  2:47   ` [PATCH 52/57] power: abx500_chargalg: Use hrtimer Anton Vorontsov
2012-09-28 18:33     ` Mathieu Poirier
2012-09-28 19:41       ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 53/57] power: ab8500_fg: Moving structure definitions to header file mathieu.poirier
2012-09-28  2:51   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 54/57] power: ab8500_charger: Use USBLink1Status Register mathieu.poirier
2012-09-28  2:56   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 55/57] power: ab8500_charger: Add UsbLineCtrl2 reference mathieu.poirier
2012-09-28  2:58   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 56/57] power: abx500_chargalg: Fix quick re-attach charger issue mathieu.poirier
2012-09-28  3:00   ` Anton Vorontsov
2012-09-25 16:12 ` [PATCH 57/57] power: ab8500_charger: Limit USB charger current mathieu.poirier
2012-09-27  3:38 ` [PATCH 00/57] power: Upgrade to ux500 battery management driver Anton Vorontsov
2012-09-27 22:08   ` Mathieu Poirier
2012-09-28  0:36     ` Anton Vorontsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1348589574-25655-53-git-send-email-mathieu.poirier@linaro.org \
    --to=mathieu.poirier@linaro.org \
    --cc=cbou@mail.ru \
    --cc=dwmw2@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).