aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2013-02-13 10:15:03 -0500
committerLee Jones <lee.jones@linaro.org>2013-03-06 23:35:49 -0500
commit257107ae6b9ba1f3822a8b079acef57a752dcc4c (patch)
treeaca50a28bc02d02d85cf705293148732993be8a4 /drivers/power
parenteaded808c9f9f36d95b5b7fe195ab1839e9e486c (diff)
ab8500-chargalg: Use hrtimer
Timers used for charging safety and maintenance must work even when CPU power has collapsed. By using hrtimers with the realtime clock the system is able to trigger an alarm that wakes-up the CPU and makes it possible to handle events. Allow a little slack time of 5 minutes for the hrtimers to allow CPU to be woken-up in a more optimal power saving way. A 5 minute delay to time-out timers relative to hours does not impact on safety. Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/abx500_chargalg.c91
1 files changed, 52 insertions, 39 deletions
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index e23b92a5332e..55c9d2ea5dff 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (C) ST-Ericsson SA 2012 2 * Copyright (C) ST-Ericsson SA 2012
3 * Copyright (c) 2012 Sony Mobile Communications AB
3 * 4 *
4 * Charging algorithm driver for abx500 variants 5 * Charging algorithm driver for abx500 variants
5 * 6 *
@@ -8,11 +9,13 @@
8 * Johan Palsson <johan.palsson@stericsson.com> 9 * Johan Palsson <johan.palsson@stericsson.com>
9 * Karl Komierowski <karl.komierowski@stericsson.com> 10 * Karl Komierowski <karl.komierowski@stericsson.com>
10 * Arun R Murthy <arun.murthy@stericsson.com> 11 * Arun R Murthy <arun.murthy@stericsson.com>
12 * Author: Imre Sunyi <imre.sunyi@sonymobile.com>
11 */ 13 */
12 14
13#include <linux/init.h> 15#include <linux/init.h>
14#include <linux/module.h> 16#include <linux/module.h>
15#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/hrtimer.h>
16#include <linux/interrupt.h> 19#include <linux/interrupt.h>
17#include <linux/delay.h> 20#include <linux/delay.h>
18#include <linux/slab.h> 21#include <linux/slab.h>
@@ -24,6 +27,7 @@
24#include <linux/of.h> 27#include <linux/of.h>
25#include <linux/mfd/core.h> 28#include <linux/mfd/core.h>
26#include <linux/mfd/abx500.h> 29#include <linux/mfd/abx500.h>
30#include <linux/mfd/abx500/ab8500.h>
27#include <linux/mfd/abx500/ux500_chargalg.h> 31#include <linux/mfd/abx500/ux500_chargalg.h>
28#include <linux/mfd/abx500/ab8500-bm.h> 32#include <linux/mfd/abx500/ab8500-bm.h>
29#include <linux/notifier.h> 33#include <linux/notifier.h>
@@ -34,6 +38,12 @@
34/* End-of-charge criteria counter */ 38/* End-of-charge criteria counter */
35#define EOC_COND_CNT 10 39#define EOC_COND_CNT 10
36 40
41/* One hour expressed in seconds */
42#define ONE_HOUR_IN_SECONDS 3600
43
44/* Five minutes expressed in seconds */
45#define FIVE_MINUTES_IN_SECONDS 300
46
37/* Plus margin for the low battery threshold */ 47/* Plus margin for the low battery threshold */
38#define BAT_PLUS_MARGIN (100) 48#define BAT_PLUS_MARGIN (100)
39 49
@@ -244,8 +254,8 @@ struct abx500_chargalg {
244 struct delayed_work chargalg_periodic_work; 254 struct delayed_work chargalg_periodic_work;
245 struct delayed_work chargalg_wd_work; 255 struct delayed_work chargalg_wd_work;
246 struct work_struct chargalg_work; 256 struct work_struct chargalg_work;
247 struct timer_list safety_timer; 257 struct hrtimer safety_timer;
248 struct timer_list maintenance_timer; 258 struct hrtimer maintenance_timer;
249 struct kobject chargalg_kobject; 259 struct kobject chargalg_kobject;
250}; 260};
251 261
@@ -260,38 +270,47 @@ static enum power_supply_property abx500_chargalg_props[] = {
260 270
261/** 271/**
262 * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer 272 * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
263 * @data: pointer to the abx500_chargalg structure 273 * @timer: pointer to the hrtimer structure
264 * 274 *
265 * This function gets called when the safety timer for the charger 275 * This function gets called when the safety timer for the charger
266 * expires 276 * expires
267 */ 277 */
268static void abx500_chargalg_safety_timer_expired(unsigned long data) 278static enum hrtimer_restart
279abx500_chargalg_safety_timer_expired(struct hrtimer *timer)
269{ 280{
270 struct abx500_chargalg *di = (struct abx500_chargalg *) data; 281 struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
282 safety_timer);
271 dev_err(di->dev, "Safety timer expired\n"); 283 dev_err(di->dev, "Safety timer expired\n");
272 di->events.safety_timer_expired = true; 284 di->events.safety_timer_expired = true;
273 285
274 /* Trigger execution of the algorithm instantly */ 286 /* Trigger execution of the algorithm instantly */
275 queue_work(di->chargalg_wq, &di->chargalg_work); 287 queue_work(di->chargalg_wq, &di->chargalg_work);
288
289 return HRTIMER_NORESTART;
276} 290}
277 291
278/** 292/**
279 * abx500_chargalg_maintenance_timer_expired() - Expiration of 293 * abx500_chargalg_maintenance_timer_expired() - Expiration of
280 * the maintenance timer 294 * the maintenance timer
281 * @i: pointer to the abx500_chargalg structure 295 * @timer: pointer to the timer structure
282 * 296 *
283 * This function gets called when the maintenence timer 297 * This function gets called when the maintenence timer
284 * expires 298 * expires
285 */ 299 */
286static void abx500_chargalg_maintenance_timer_expired(unsigned long data) 300static enum hrtimer_restart
301abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer)
287{ 302{
288 303
289 struct abx500_chargalg *di = (struct abx500_chargalg *) data; 304 struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
305 maintenance_timer);
306
290 dev_dbg(di->dev, "Maintenance timer expired\n"); 307 dev_dbg(di->dev, "Maintenance timer expired\n");
291 di->events.maintenance_timer_expired = true; 308 di->events.maintenance_timer_expired = true;
292 309
293 /* Trigger execution of the algorithm instantly */ 310 /* Trigger execution of the algorithm instantly */
294 queue_work(di->chargalg_wq, &di->chargalg_work); 311 queue_work(di->chargalg_wq, &di->chargalg_work);
312
313 return HRTIMER_NORESTART;
295} 314}
296 315
297/** 316/**
@@ -391,19 +410,16 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
391 */ 410 */
392static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) 411static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
393{ 412{
394 unsigned long timer_expiration = 0; 413 /* Charger-dependent expiration time in hours*/
414 int timer_expiration = 0;
395 415
396 switch (di->chg_info.charger_type) { 416 switch (di->chg_info.charger_type) {
397 case AC_CHG: 417 case AC_CHG:
398 timer_expiration = 418 timer_expiration = di->bm->main_safety_tmr_h;
399 round_jiffies(jiffies +
400 (di->bm->main_safety_tmr_h * 3600 * HZ));
401 break; 419 break;
402 420
403 case USB_CHG: 421 case USB_CHG:
404 timer_expiration = 422 timer_expiration = di->bm->usb_safety_tmr_h;
405 round_jiffies(jiffies +
406 (di->bm->usb_safety_tmr_h * 3600 * HZ));
407 break; 423 break;
408 424
409 default: 425 default:
@@ -412,11 +428,10 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
412 } 428 }
413 429
414 di->events.safety_timer_expired = false; 430 di->events.safety_timer_expired = false;
415 di->safety_timer.expires = timer_expiration; 431 hrtimer_set_expires_range(&di->safety_timer,
416 if (!timer_pending(&di->safety_timer)) 432 ktime_set(timer_expiration * ONE_HOUR_IN_SECONDS, 0),
417 add_timer(&di->safety_timer); 433 ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
418 else 434 hrtimer_start_expires(&di->safety_timer, HRTIMER_MODE_REL);
419 mod_timer(&di->safety_timer, timer_expiration);
420} 435}
421 436
422/** 437/**
@@ -427,8 +442,8 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
427 */ 442 */
428static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di) 443static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
429{ 444{
430 di->events.safety_timer_expired = false; 445 if (hrtimer_try_to_cancel(&di->safety_timer) >= 0)
431 del_timer(&di->safety_timer); 446 di->events.safety_timer_expired = false;
432} 447}
433 448
434/** 449/**
@@ -443,17 +458,11 @@ static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
443static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di, 458static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
444 int duration) 459 int duration)
445{ 460{
446 unsigned long timer_expiration; 461 hrtimer_set_expires_range(&di->maintenance_timer,
447 462 ktime_set(duration * ONE_HOUR_IN_SECONDS, 0),
448 /* Convert from hours to jiffies */ 463 ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
449 timer_expiration = round_jiffies(jiffies + (duration * 3600 * HZ));
450
451 di->events.maintenance_timer_expired = false; 464 di->events.maintenance_timer_expired = false;
452 di->maintenance_timer.expires = timer_expiration; 465 hrtimer_start_expires(&di->maintenance_timer, HRTIMER_MODE_REL);
453 if (!timer_pending(&di->maintenance_timer))
454 add_timer(&di->maintenance_timer);
455 else
456 mod_timer(&di->maintenance_timer, timer_expiration);
457} 466}
458 467
459/** 468/**
@@ -465,8 +474,8 @@ static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
465 */ 474 */
466static void abx500_chargalg_stop_maintenance_timer(struct abx500_chargalg *di) 475static void abx500_chargalg_stop_maintenance_timer(struct abx500_chargalg *di)
467{ 476{
468 di->events.maintenance_timer_expired = false; 477 if (hrtimer_try_to_cancel(&di->maintenance_timer) >= 0)
469 del_timer(&di->maintenance_timer); 478 di->events.maintenance_timer_expired = false;
470} 479}
471 480
472/** 481/**
@@ -1937,10 +1946,16 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
1937 /* sysfs interface to enable/disbale charging from user space */ 1946 /* sysfs interface to enable/disbale charging from user space */
1938 abx500_chargalg_sysfs_exit(di); 1947 abx500_chargalg_sysfs_exit(di);
1939 1948
1949 hrtimer_cancel(&di->safety_timer);
1950 hrtimer_cancel(&di->maintenance_timer);
1951
1952 cancel_delayed_work_sync(&di->chargalg_periodic_work);
1953 cancel_delayed_work_sync(&di->chargalg_wd_work);
1954 cancel_work_sync(&di->chargalg_work);
1955
1940 /* Delete the work queue */ 1956 /* Delete the work queue */
1941 destroy_workqueue(di->chargalg_wq); 1957 destroy_workqueue(di->chargalg_wq);
1942 1958
1943 flush_scheduled_work();
1944 power_supply_unregister(&di->chargalg_psy); 1959 power_supply_unregister(&di->chargalg_psy);
1945 platform_set_drvdata(pdev, NULL); 1960 platform_set_drvdata(pdev, NULL);
1946 1961
@@ -1994,15 +2009,13 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
1994 abx500_chargalg_external_power_changed; 2009 abx500_chargalg_external_power_changed;
1995 2010
1996 /* Initilialize safety timer */ 2011 /* Initilialize safety timer */
1997 init_timer(&di->safety_timer); 2012 hrtimer_init(&di->safety_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
1998 di->safety_timer.function = abx500_chargalg_safety_timer_expired; 2013 di->safety_timer.function = abx500_chargalg_safety_timer_expired;
1999 di->safety_timer.data = (unsigned long) di;
2000 2014
2001 /* Initilialize maintenance timer */ 2015 /* Initilialize maintenance timer */
2002 init_timer(&di->maintenance_timer); 2016 hrtimer_init(&di->maintenance_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
2003 di->maintenance_timer.function = 2017 di->maintenance_timer.function =
2004 abx500_chargalg_maintenance_timer_expired; 2018 abx500_chargalg_maintenance_timer_expired;
2005 di->maintenance_timer.data = (unsigned long) di;
2006 2019
2007 /* Create a work queue for the chargalg */ 2020 /* Create a work queue for the chargalg */
2008 di->chargalg_wq = 2021 di->chargalg_wq =