power: max77665: add watchdog timer for charging
Rakesh Bodla [Thu, 28 Mar 2013 07:12:21 +0000 (12:12 +0530)]
Bug 1242272

Change-Id: Ie09fccea64c0953be0120b505557bc791ed150ca
Signed-off-by: Xin Xie <xxie@nvidia.com>
Signed-off-by: Rakesh Bodla <rbodla@nvidia.com>
Reviewed-on: http://git-master/r/207405
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>

drivers/power/max77665-charger.c
include/linux/max77665-charger.h

index 2feff82..010a5f7 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
+#include <linux/alarmtimer.h>
+#include <linux/timer.h>
+#include <linux/wakelock.h>
 #include <linux/mfd/max77665.h>
 #include <linux/max77665-charger.h>
 #include <linux/power/max17042_battery.h>
@@ -68,6 +71,9 @@ struct max77665_charger {
        uint8_t usb_online;
        uint8_t num_cables;
        struct extcon_dev *edev;
+       struct alarm wdt_alarm;
+       struct delayed_work wdt_ack_work;
+       struct wake_lock wdt_wake_lock;
 };
 
 static enum power_supply_property max77665_ac_props[] = {
@@ -185,6 +191,7 @@ static int max77665_charger_enable(struct max77665_charger *charger,
                enum max77665_mode mode)
 {
        int ret;
+       int flags;
 
        ret = max77665_enable_write(charger, true);
        if (ret < 0) {
@@ -194,12 +201,14 @@ static int max77665_charger_enable(struct max77665_charger *charger,
 
        if (mode == CHARGER) {
                /* enable charging */
-               ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_00, 0x05);
+               flags = CHARGER_ON_OTG_OFF_BUCK_OFF_BOOST_ON | WDTEN;
+               ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_00, flags);
                if (ret < 0)
                        return ret;
        } else if (mode == OTG) {
                /* enable OTG mode */
-               ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_00, 0x2A);
+               flags = CHARGER_OFF_OTG_ON_BUCK_OFF_BOOST_ON;
+               ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_00, flags);
                if (ret < 0)
                        return ret;
        }
@@ -329,55 +338,93 @@ static int max77665_enable_charger(struct max77665_charger *charger)
                goto error;
        }
 
+       /* set the charging watchdog timer */
+       alarm_start(&charger->wdt_alarm, ktime_add(ktime_get_boottime(),
+                       ktime_set(MAX77665_WATCHDOG_TIMER_PERIOD_S / 2, 0)));
+
        return 0;
 error:
        return ret;
 }
 
+static void max77665_charger_wdt_ack_work_handler(struct work_struct *w)
+{
+       struct max77665_charger *charger = container_of(to_delayed_work(w),
+                       struct max77665_charger, wdt_ack_work);
+
+       if (0 > max77665_update_reg(charger, MAX77665_CHG_CNFG_06, WDTCLR))
+               dev_err(charger->dev, "fail to ack charging WDT\n");
+
+       alarm_start(&charger->wdt_alarm,
+                       ktime_add(ktime_get_boottime(), ktime_set(30, 0)));
+       wake_unlock(&charger->wdt_wake_lock);
+}
+
+static enum alarmtimer_restart max77665_charger_wdt_timer(struct alarm *alarm,
+               ktime_t now)
+{
+       struct max77665_charger *charger =
+               container_of(alarm, struct max77665_charger, wdt_alarm);
+
+       wake_lock(&charger->wdt_wake_lock);
+       schedule_delayed_work(&charger->wdt_ack_work, 0);
+       return ALARMTIMER_NORESTART;
+}
+
+static void max77665_charger_disable_wdt(struct max77665_charger *charger)
+{
+       cancel_delayed_work_sync(&charger->wdt_ack_work);
+       alarm_cancel(&charger->wdt_alarm);
+}
+
 static int charger_extcon_notifier(struct notifier_block *self,
                unsigned long event, void *ptr)
 {
+       /* Need to disable watch dog timer if cable is added */
        return NOTIFY_DONE;
 }
 
+static int max77665_display_charger_status(struct max77665_charger *charger,
+               uint32_t val)
+{
+       int i;
+       int bits[] = { BYP_OK, DETBAT_OK, BAT_OK, CHG_OK, CHGIN_OK };
+       char *info[] = {
+               "bypass",
+               "main battery presence",
+               "battery",
+               "charger",
+               "charging input"
+       };
+
+       for (i = 0; i < ARRAY_SIZE(bits); i++)
+               dev_err(charger->dev, "%s %s OK", info[i],
+                       (val & bits[i]) ? "is" : "is not");
+
+       return 0;
+}
+
 static int max77665_update_charger_status(struct max77665_charger *charger)
 {
        int ret;
        uint32_t read_val;
 
-       ret = max77665_read_reg(charger, MAX77665_CHG_INT_OK, &read_val);
+       ret = max77665_read_reg(charger, MAX77665_CHG_INT, &read_val);
        if (ret < 0) {
-               dev_err(charger->dev, "failed to write to reg: 0x%x\n",
-                               MAX77665_CHG_INT_OK);
+               dev_err(charger->dev, "failed in reading register: 0x%x\n",
+                               MAX77665_CHG_INT);
                goto error;
        }
 
-       if (read_val & 0x40) {
-               charger->usb_online = 1;
-               power_supply_changed(&charger->usb);
-               power_supply_changed(&charger->ac);
-               ret = max77665_enable_charger(charger);
-               if (ret < 0)
-                       goto error;
-       } else {
-               charger->ac_online = 0;
-               charger->usb_online = 0;
-               if (charger->plat_data->update_status)
-                       charger->plat_data->update_status(false);
-               power_supply_changed(&charger->usb);
-               power_supply_changed(&charger->ac);
-       }
-
-       ret = max77665_read_reg(charger, MAX77665_CHG_INT, &read_val);
+       ret = max77665_read_reg(charger, MAX77665_CHG_INT_OK, &read_val);
        if (ret < 0) {
-               dev_err(charger->dev, "failed in reading register: 0x%x\n",
-                               MAX77665_CHG_INT);
+               dev_err(charger->dev, "failed to reading reg: 0x%x\n",
+                               MAX77665_CHG_INT_OK);
                goto error;
        }
+       max77665_display_charger_status(charger, read_val);
 
        ret = max77665_write_reg(charger, MAX77665_CHG_INT_MASK, 0x0a);
-       if (ret < 0)
-               goto error;
 error:
        return ret;
 }
@@ -506,6 +553,13 @@ static __devinit int max77665_battery_probe(struct platform_device *pdev)
                goto chrg_error;
        }
 
+       wake_lock_init(&charger->wdt_wake_lock, WAKE_LOCK_SUSPEND,
+                       "max77665-charger-wdt");
+       alarm_init(&charger->wdt_alarm, ALARM_BOOTTIME,
+                       max77665_charger_wdt_timer);
+       INIT_DELAYED_WORK(&charger->wdt_ack_work,
+                       max77665_charger_wdt_ack_work_handler);
+
        return 0;
 
 chrg_error:
index 591d165..28c7b54 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MAX77665 Haptic Driver
  *
-  * Copyright (C) 2012 nVIDIA corporation
+ * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  * Author: Syed Rafiuddin <srafiuddin@nvidia.com>
  *
  * This program is free software; you can redistribute it and/or modify it
 #define MAX77665_CHG_INT        0xb0
 #define MAX77665_CHG_INT_MASK   0xb1
 #define MAX77665_CHG_INT_OK     0xb2
+#define BYP_OK                 (1 << 0)
+#define DETBAT_OK              (1 << 2)
+#define BAT_OK                 (1 << 3)
+#define CHG_OK                 (1 << 4)
+#define CHGIN_OK               (1 << 6)
 #define MAX77665_CHG_DTLS_00    0xb3
 #define MAX77665_CHG_DTLS_01    0xb4
 #define MAX77665_CHG_DTLS_02    0xb5
 #define MAX77665_CHG_DTLS_03    0xb6
 #define MAX77665_CHG_CNFG_00    0xb7
+#define CHARGER_ON_OTG_OFF_BUCK_OFF_BOOST_ON 0x05
+#define CHARGER_OFF_OTG_ON_BUCK_OFF_BOOST_ON 0x2A
+#define WDTEN  (1 << 4)
 #define MAX77665_CHG_CNFG_01    0xb8
 #define MAX77665_CHG_CNFG_02    0xb9
 #define MAX77665_CHG_CNFG_03    0xba
 #define MAX77665_CHG_CNFG_04    0xbb
 #define MAX77665_CHG_CNFG_05    0xbc
 #define MAX77665_CHG_CNFG_06    0xbd
+#define WDTCLR (1 << 0)
 #define MAX77665_CHG_CNFG_07    0xbe
 #define MAX77665_CHG_CNFG_08    0xbf
 #define MAX77665_CHG_CNFG_09    0xc0
@@ -48,6 +57,7 @@
 #define MAX77665_CHG_CNFG_13    0xc4
 #define MAX77665_CHG_CNFG_14    0xc5
 #define MAX77665_SAFEOUTCTRL    0xc6
+#define MAX77665_WATCHDOG_TIMER_PERIOD_S 80
 
 #define MAX_CABLES     6