aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 =