power: bq2419x: Implement WDT timer
Syed Rafiuddin [Wed, 3 Apr 2013 08:36:34 +0000 (13:36 +0530)]
BQ2419X support the WDT timer which reset the configuration
on expiration. Handling the WDT timer to proper functiong of device.

Following are details of changes:
- Implement WDT reset in kthread with high priority.
- Configure WDT time based on platform data,
- Merge the VBUS regulator in the charger driver itself as
charger or VBUS can happen mutually.
- Displaying the charging fault when happens.
- Other cleanups to reduce code size and make better readability.
- Related chnages in board file.

Bug 1240114
Bug 1260994

Change-Id: Iefa79b7c0c791e8a1d69b44d9399aab7730a2da9
Signed-off-by: Syed Rafiuddin <srafiuddin@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Hyongbin Kim <hyongbink@nvidia.com>
Reviewed-on: http://git-master/r/205495
(cherry picked from commit b2183dca8729336665f97a19a0e6edfd588a248e)
Reviewed-on: http://git-master/r/216077
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>

arch/arm/configs/tegra11_android_defconfig
arch/arm/mach-tegra/board-macallan-power.c
arch/arm/mach-tegra/board-roth-power.c
arch/arm/mach-tegra/board-tegratab-power.c
drivers/power/Kconfig
drivers/power/bq2419x-charger.c
include/linux/power/bq2419x-charger.h [new file with mode: 0644]

index b283fd0..c3ba839 100644 (file)
@@ -324,7 +324,6 @@ CONFIG_THERMAL_GOV_PID=y
 CONFIG_PWM_FAN=y
 CONFIG_WATCHDOG=y
 CONFIG_PALMAS_WATCHDOG=y
-CONFIG_MFD_BQ2419X=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
 CONFIG_AIC3XXX_CORE=y
@@ -341,7 +340,6 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
 CONFIG_REGULATOR_USERSPACE_CONSUMER=y
 CONFIG_REGULATOR_GPIO=y
-CONFIG_REGULATOR_BQ2419X=y
 CONFIG_REGULATOR_MAX8973=y
 CONFIG_REGULATOR_MAX77663=y
 CONFIG_REGULATOR_RC5T583=y
index eb1659b..612d55c 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/fixed.h>
 #include <linux/mfd/palmas.h>
-#include <linux/mfd/bq2419x.h>
+#include <linux/power/bq2419x-charger.h>
 #include <linux/max17048_battery.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
@@ -62,17 +62,8 @@ static struct regulator_consumer_supply bq2419x_vbus_supply[] = {
        REGULATOR_SUPPLY("usb_vbus", "tegra-ehci.0"),
 };
 
-static struct regulator_init_data bq2419x_init_data = {
-       .constraints = {
-               .name = "bq2419x_vbus",
-               .min_uV = 0,
-               .max_uV = 5000000,
-               .valid_modes_mask = (REGULATOR_MODE_NORMAL |
-                                       REGULATOR_MODE_STANDBY),
-               .valid_ops_mask = (REGULATOR_CHANGE_MODE |
-                                       REGULATOR_CHANGE_STATUS |
-                                       REGULATOR_CHANGE_VOLTAGE),
-       },
+static struct bq2419x_vbus_platform_data bq2419x_vbus_pdata = {
+       .gpio_otg_iusb = TEGRA_GPIO_PI4,
        .num_consumer_supplies = ARRAY_SIZE(bq2419x_vbus_supply),
        .consumer_supplies = bq2419x_vbus_supply,
 };
@@ -84,8 +75,7 @@ static struct bq2419x_regulator_platform_data bq2419x_reg_pdata = {
 };
 
 struct bq2419x_platform_data macallan_bq2419x_pdata = {
-       .reg_pdata = &bq2419x_reg_pdata,
-       .disable_watchdog = true,
+       .vbus_pdata = &bq2419x_vbus_pdata,
 };
 
 static struct i2c_board_info __initdata bq2419x_boardinfo[] = {
index f3d1d7a..dafd856 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/mfd/palmas.h>
 #include <linux/regulator/tps51632-regulator.h>
-#include <linux/mfd/bq2419x.h>
+#include <linux/power/bq2419x-charger.h>
 #include <linux/max17048_battery.h>
 #include <linux/gpio.h>
 #include <linux/regulator/userspace-consumer.h>
@@ -103,37 +103,22 @@ static struct regulator_consumer_supply bq2419x_batt_supply[] = {
        REGULATOR_SUPPLY("usb_bat_chg", "tegra-udc.0"),
 };
 
-static struct regulator_init_data bq2419x_init_data = {
-       .constraints = {
-               .name = "bq2419x_vbus",
-               .min_uV = 0,
-               .max_uV = 5000000,
-               .valid_modes_mask = (REGULATOR_MODE_NORMAL |
-                                       REGULATOR_MODE_STANDBY),
-               .valid_ops_mask = (REGULATOR_CHANGE_MODE |
-                                       REGULATOR_CHANGE_STATUS |
-                                       REGULATOR_CHANGE_VOLTAGE),
-       },
+static struct bq2419x_vbus_platform_data bq2419x_vbus_pdata = {
+       .gpio_otg_iusb = TEGRA_GPIO_PI4,
        .num_consumer_supplies = ARRAY_SIZE(bq2419x_vbus_supply),
        .consumer_supplies = bq2419x_vbus_supply,
 };
 
-static struct bq2419x_regulator_platform_data bq2419x_reg_pdata = {
-       .reg_init_data = &bq2419x_init_data,
-       .gpio_otg_iusb = TEGRA_GPIO_PI4,
-};
-
 struct bq2419x_charger_platform_data bq2419x_charger_pdata = {
        .use_usb = 1,
        .use_mains = 1,
-       .gpio_interrupt = TEGRA_GPIO_PJ0,
-       .gpio_status = TEGRA_GPIO_PK0,
        .update_status = max17048_battery_status,
        .battery_check = max17048_check_battery,
        .max_charge_current_mA = 3000,
        .charging_term_current_mA = 100,
        .consumer_supplies = bq2419x_batt_supply,
        .num_consumer_supplies = ARRAY_SIZE(bq2419x_batt_supply),
+       .wdt_timeout    = 40,
 };
 
 struct max17048_battery_model max17048_mdata = {
@@ -158,7 +143,7 @@ struct max17048_battery_model max17048_mdata = {
                0x1F, 0xE0, 0x1F, 0xE0, 0x11, 0xC0, 0x11, 0x20,
                0x14, 0x60, 0x0B, 0xE0, 0x14, 0x80, 0x14, 0xC0,
                0x0E, 0x20, 0x12, 0xA0, 0x03, 0x60, 0x03, 0x60,
-        },
+       },
 };
 
 struct max17048_platform_data max17048_pdata = {
@@ -175,9 +160,8 @@ static struct i2c_board_info __initdata max17048_boardinfo[] = {
 };
 
 struct bq2419x_platform_data bq2419x_pdata = {
-       .reg_pdata = &bq2419x_reg_pdata,
+       .vbus_pdata = &bq2419x_vbus_pdata,
        .bcharger_pdata = &bq2419x_charger_pdata,
-       .disable_watchdog = true,
 };
 
 static struct i2c_board_info __initdata bq2419x_boardinfo[] = {
@@ -745,6 +729,7 @@ int __init roth_regulator_init(void)
        tegra_get_board_info(&board_info);
        roth_palmas_regulator_init();
 
+       bq2419x_boardinfo[0].irq = gpio_to_irq(TEGRA_GPIO_PJ0);
        i2c_register_board_info(4, tps51632_boardinfo, 1);
        i2c_register_board_info(0, max17048_boardinfo, 1);
        i2c_register_board_info(0, bq2419x_boardinfo, 1);
index 7fd0b14..4b53717 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/fixed.h>
 #include <linux/mfd/palmas.h>
-#include <linux/mfd/bq2419x.h>
+#include <linux/power/bq2419x-charger.h>
 #include <linux/max17048_battery.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
@@ -66,38 +66,22 @@ static struct regulator_consumer_supply tegratab_bq2419x_batt_supply[] = {
        REGULATOR_SUPPLY("usb_bat_chg", "tegra-udc.0"),
 };
 
-static struct regulator_init_data tegratab_bq2419x_init_data = {
-       .constraints = {
-               .name = "bq2419x_vbus",
-               .min_uV = 0,
-               .max_uV = 5000000,
-               .valid_modes_mask = (REGULATOR_MODE_NORMAL |
-                                       REGULATOR_MODE_STANDBY),
-               .valid_ops_mask = (REGULATOR_CHANGE_MODE |
-                                       REGULATOR_CHANGE_STATUS |
-                                       REGULATOR_CHANGE_VOLTAGE),
-       },
+static struct bq2419x_vbus_platform_data tegratab_bq2419x_vbus_pdata = {
+       .gpio_otg_iusb = TEGRA_GPIO_PI4,
        .num_consumer_supplies = ARRAY_SIZE(tegratab_bq2419x_vbus_supply),
        .consumer_supplies = tegratab_bq2419x_vbus_supply,
 };
 
-static struct bq2419x_regulator_platform_data tegratab_bq2419x_reg_pdata = {
-       .reg_init_data = &tegratab_bq2419x_init_data,
-       .gpio_otg_iusb = TEGRA_GPIO_PI4,
-       .power_off_on_suspend = true,
-};
-
 struct bq2419x_charger_platform_data tegratab_bq2419x_charger_pdata = {
        .use_usb = 1,
        .use_mains = 1,
-       .gpio_interrupt = TEGRA_GPIO_PJ0,
-       .gpio_status = TEGRA_GPIO_PK0,
        .update_status = max17048_battery_status,
        .battery_check = max17048_check_battery,
        .max_charge_current_mA = 3000,
        .charging_term_current_mA = 100,
        .consumer_supplies = tegratab_bq2419x_batt_supply,
        .num_consumer_supplies = ARRAY_SIZE(tegratab_bq2419x_batt_supply),
+       .wdt_timeout    = 40,
 };
 
 struct max17048_battery_model tegratab_max17048_mdata = {
@@ -139,15 +123,14 @@ static struct i2c_board_info __initdata tegratab_max17048_boardinfo[] = {
 };
 
 struct bq2419x_platform_data tegratab_bq2419x_pdata = {
-       .reg_pdata = &tegratab_bq2419x_reg_pdata,
+       .vbus_pdata = &tegratab_bq2419x_vbus_pdata,
        .bcharger_pdata = &tegratab_bq2419x_charger_pdata,
-       .disable_watchdog = true,
 };
 
 static struct i2c_board_info __initdata tegratab_bq2419x_boardinfo[] = {
        {
                I2C_BOARD_INFO("bq2419x", 0x6b),
-               .platform_data  = &tegratab_bq2419x_pdata,
+               .platform_data = &tegratab_bq2419x_pdata,
        },
 };
 
@@ -670,11 +653,12 @@ int __init tegratab_regulator_init(void)
 #endif
        tegratab_palmas_regulator_init();
 
+       i2c_register_board_info(0, tegratab_max17048_boardinfo, 1);
+
        /* Disable charger when adapter is power source. */
        if (get_power_supply_type() != POWER_SUPPLY_TYPE_BATTERY)
                tegratab_bq2419x_pdata.bcharger_pdata = NULL;
 
-       i2c_register_board_info(0, tegratab_max17048_boardinfo, 1);
        i2c_register_board_info(0, tegratab_bq2419x_boardinfo, 1);
 
        platform_device_register(&tegratab_pda_power_device);
index 291b1ca..f29f4c0 100644 (file)
@@ -23,10 +23,11 @@ config PDA_POWER
          backup batteries, and optional builtin charger.
 
 config CHARGER_BQ2419X
-       tristate "BQ2419X charger support"
-       depends on MFD_BQ2419X
+       tristate "BQ24190/BQ24192/BQ24192i/BQ24193 Charger driver support"
+       depends on I2C
        help
-         Say Y here to enable support for TI BQ2419X charger.
+         Say Y here to enable support for TI BQ24190/BQ24192/BQ24192i/BQ24193
+         Charger.
 
 config APM_POWER
        tristate "APM emulation for class batteries"
index 71ba78b..c47cf56 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * bq2419x-charger.c - Battery charger driver
+ * bq2419x-charger.c -- BQ24190/BQ24192/BQ24192i/BQ24193 Charger driver
  *
  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ * Author: Syed Rafiuddin <srafiuddin@nvidia.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/mfd/bq2419x.h>
-#include <linux/regmap.h>
-#include <linux/platform_device.h>
+#include <linux/power/bq2419x-charger.h>
 #include <linux/power_supply.h>
-#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/slab.h>
 
 /* input current limit */
 static const unsigned int iinlim[] = {
        100, 150, 500, 900, 1200, 1500, 2000, 3000,
 };
 
-struct bq2419x_charger {
-       struct device           *dev;
-       struct bq2419x_chip     *chip;
-       struct power_supply     ac;
-       struct power_supply     usb;
-       int                     ac_online;
-       int                     usb_online;
-       int                     gpio_status;
-       int                     gpio_interrupt;
-       int                     in_current_limit;
-       unsigned                use_mains:1;
-       unsigned                use_usb:1;
-       int status;
-       void (*update_status)(int, int);
-       struct regulator_dev    *rdev;
-       struct regulator_desc   reg_desc;
-       struct regulator_init_data      reg_init_data;
-       int                     shutdown_complete;
-       struct mutex            mutex;
-       struct mutex            chrg_mutex;
+/* Kthread scheduling parameters */
+struct sched_param bq2419x_param = {
+       .sched_priority = MAX_RT_PRIO - 1,
 };
 
-struct bq2419x_charger *bq_charger;
+static const struct regmap_config bq2419x_regmap_config = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = BQ2419X_MAX_REGS,
+};
+
+struct bq2419x_chip {
+       struct device                   *dev;
+       struct regmap                   *regmap;
+       int                             irq;
+       int                             gpio_otg_iusb;
+       int                             wdt_refresh_timeout;
+
+       struct power_supply             ac;
+       struct power_supply             usb;
+       int                             ac_online;
+       int                             usb_online;
+       int                             in_current_limit;
+       unsigned                        use_mains:1;
+       unsigned                        use_usb:1;
+       int                             status;
+       void                            (*update_status)(int, int);
+
+       struct regulator_dev            *chg_rdev;
+       struct regulator_desc           chg_reg_desc;
+       struct regulator_init_data      chg_reg_init_data;
+
+       struct regulator_dev            *vbus_rdev;
+       struct regulator_desc           vbus_reg_desc;
+       struct regulator_init_data      vbus_reg_init_data;
+
+       struct kthread_worker           bq_kworker;
+       struct task_struct              *bq_kworker_task;
+       struct kthread_work             bq_wdt_work;
+       int                             stop_thread;
+};
 
 static enum power_supply_property bq2419x_psy_props[] = {
        POWER_SUPPLY_PROP_ONLINE,
 };
+
 static int current_to_reg(const unsigned int *tbl,
                        size_t size, unsigned int val)
 {
@@ -78,32 +102,87 @@ static int current_to_reg(const unsigned int *tbl,
        return i > 0 ? i - 1 : -EINVAL;
 }
 
-static int bq2419x_charger_enable(struct bq2419x_charger *charger)
+static int bq2419x_charger_enable(struct bq2419x_chip *bq2419x)
 {
        int ret;
-       mutex_lock(&charger->mutex);
-       if (charger && charger->shutdown_complete) {
-               mutex_unlock(&charger->mutex);
-               return -ENODEV;
-       }
-       mutex_unlock(&charger->mutex);
 
-       dev_info(charger->dev, "Charging enabled\n");
-       ret = regmap_update_bits(charger->chip->regmap, BQ2419X_PWR_ON_REG,
-                               ENABLE_CHARGE_MASK, ENABLE_CHARGE);
+       dev_info(bq2419x->dev, "Charging enabled\n");
+       ret = regmap_update_bits(bq2419x->regmap, BQ2419X_PWR_ON_REG,
+                       BQ2419X_ENABLE_CHARGE_MASK, BQ2419X_ENABLE_CHARGE);
        if (ret < 0)
-               dev_err(charger->dev, "register update failed, err %d\n", ret);
+               dev_err(bq2419x->dev, "register update failed, err %d\n", ret);
+       return ret;
+}
+
+static int bq2419x_vbus_regulator_enable_time(struct regulator_dev *rdev)
+{
+       return 500000;
+}
+
+static int bq2419x_vbus_enable(struct regulator_dev *rdev)
+{
+       struct bq2419x_chip *bq2419x = rdev_get_drvdata(rdev);
+       int ret;
+
+       dev_info(bq2419x->dev, "VBUS enabled, charging disabled\n");
+       if (gpio_is_valid(bq2419x->gpio_otg_iusb))
+               gpio_set_value(bq2419x->gpio_otg_iusb, 1);
+
+       ret = regmap_update_bits(bq2419x->regmap, BQ2419X_PWR_ON_REG,
+                       BQ2419X_ENABLE_CHARGE_MASK, BQ2419X_ENABLE_VBUS);
+       if (ret < 0)
+               dev_err(bq2419x->dev, "PWR_ON_REG update failed %d", ret);
+
+       return ret;
+}
+
+static int bq2419x_vbus_disable(struct regulator_dev *rdev)
+{
+       struct bq2419x_chip *bq2419x = rdev_get_drvdata(rdev);
+       int ret;
+
+       dev_info(bq2419x->dev, "VBUS disabled, charging enabled\n");
+       ret = bq2419x_charger_enable(bq2419x);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "Charger enable failed %d", ret);
+               return ret;
+       }
+
+       if (gpio_is_valid(bq2419x->gpio_otg_iusb))
+               gpio_set_value(bq2419x->gpio_otg_iusb, 0);
+
        return ret;
 }
 
+static int bq2419x_vbus_is_enabled(struct regulator_dev *rdev)
+{
+       struct bq2419x_chip *bq2419x = rdev_get_drvdata(rdev);
+       int ret;
+       unsigned int data;
+
+       ret = regmap_read(bq2419x->regmap, BQ2419X_PWR_ON_REG, &data);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "PWR_ON_REG read failed %d", ret);
+               return ret;
+       }
+       return (data & BQ2419X_ENABLE_CHARGE_MASK) == BQ2419X_ENABLE_VBUS;
+}
+
+static struct regulator_ops bq2419x_vbus_ops = {
+       .enable         = bq2419x_vbus_enable,
+       .disable        = bq2419x_vbus_disable,
+       .is_enabled     = bq2419x_vbus_is_enabled,
+       .enable_time    = bq2419x_vbus_regulator_enable_time,
+};
+
 static int bq2419x_ac_get_property(struct power_supply *psy,
        enum power_supply_property psp, union power_supply_propval *val)
 {
-       struct bq2419x_charger *chip;
+       struct bq2419x_chip *bq2419x;
 
-       chip = container_of(psy, struct bq2419x_charger, ac);
+       bq2419x = container_of(psy, struct bq2419x_chip, ac);
        if (psp == POWER_SUPPLY_PROP_ONLINE)
-               val->intval = chip->ac_online;
+               val->intval = bq2419x->ac_online;
        else
                return -EINVAL;
        return 0;
@@ -113,68 +192,57 @@ static int bq2419x_usb_get_property(struct power_supply *psy,
                enum power_supply_property psp,
                union power_supply_propval *val)
 {
-       struct bq2419x_charger *chip;
+       struct bq2419x_chip *bq2419x;
 
-       chip = container_of(psy, struct bq2419x_charger, usb);
+       bq2419x = container_of(psy, struct bq2419x_chip, usb);
        if (psp == POWER_SUPPLY_PROP_ONLINE)
-               val->intval = chip->usb_online;
+               val->intval = bq2419x->usb_online;
        else
                return -EINVAL;
        return 0;
 }
 
-static int bq2419x_init(struct bq2419x_charger *charger)
+static int bq2419x_init(struct bq2419x_chip *bq2419x)
 {
        int val, ret = 0;
 
-       mutex_lock(&charger->mutex);
-       if (charger && charger->shutdown_complete) {
-               mutex_unlock(&charger->mutex);
-               return -ENODEV;
-       }
-       mutex_unlock(&charger->mutex);
-
        /* Clear EN_HIZ */
-       ret = regmap_update_bits(charger->chip->regmap,
+       ret = regmap_update_bits(bq2419x->regmap,
                        BQ2419X_INPUT_SRC_REG, BQ2419X_EN_HIZ, 0);
        if (ret < 0) {
-               dev_err(charger->dev, "error reading reg: 0x%x\n",
+               dev_err(bq2419x->dev, "error reading reg: 0x%x\n",
                        BQ2419X_INPUT_SRC_REG);
                return ret;
        }
+
        /* Configure input current limit */
        val = current_to_reg(iinlim, ARRAY_SIZE(iinlim),
-                               charger->in_current_limit);
+                               bq2419x->in_current_limit);
        if (val < 0)
                return 0;
 
-       ret = regmap_update_bits(charger->chip->regmap,
+       ret = regmap_update_bits(bq2419x->regmap,
                        BQ2419X_INPUT_SRC_REG, BQ2419x_CONFIG_MASK, val);
        if (ret < 0)
-               dev_err(charger->dev, "error reading reg: 0x%x\n",
+               dev_err(bq2419x->dev, "error reading reg: 0x%x\n",
                        BQ2419X_INPUT_SRC_REG);
        return ret;
 }
 
-static int bq2419x_enable_charger(struct regulator_dev *rdev,
+static int bq2419x_set_charging_current(struct regulator_dev *rdev,
                                        int min_uA, int max_uA)
 {
+       struct bq2419x_chip *bq_charger = rdev_get_drvdata(rdev);
        int ret = 0;
        int val;
 
+       dev_info(bq_charger->dev, "Setting charging current %d\n", max_uA/1000);
        msleep(200);
        bq_charger->usb_online = 0;
        bq_charger->ac_online = 0;
        bq_charger->status = 0;
 
-       mutex_lock(&bq_charger->chrg_mutex);
-       if (bq_charger && bq_charger->shutdown_complete) {
-               mutex_unlock(&bq_charger->chrg_mutex);
-               return -ENODEV;
-       }
-       mutex_unlock(&bq_charger->chrg_mutex);
-
-       ret = regmap_read(bq_charger->chip->regmap, BQ2419X_SYS_STAT_REG, &val);
+       ret = regmap_read(bq_charger->regmap, BQ2419X_SYS_STAT_REG, &val);
        if (ret < 0)
                dev_err(bq_charger->dev, "error reading reg: 0x%x\n",
                                BQ2419X_SYS_STAT_REG);
@@ -182,6 +250,7 @@ static int bq2419x_enable_charger(struct regulator_dev *rdev,
        if (max_uA == 0 && val != 0)
                return ret;
 
+       bq_charger->in_current_limit = max_uA/1000;
        if ((val & BQ2419x_VBUS_STAT) == BQ2419x_VBUS_UNKNOWN) {
                bq_charger->status = 0;
                bq_charger->usb_online = 0;
@@ -192,20 +261,18 @@ static int bq2419x_enable_charger(struct regulator_dev *rdev,
                if (bq_charger->update_status)
                        bq_charger->update_status
                                (bq_charger->status, 0);
-       } else if ((val & BQ2419x_VBUS_STAT) == BQ2419x_VBUS_USB) {
+       } else if (bq_charger->in_current_limit == 500) {
                bq_charger->status = 1;
                bq_charger->usb_online = 1;
-               bq_charger->in_current_limit = max_uA/1000;
                ret = bq2419x_init(bq_charger);
                if (ret < 0)
                        goto error;
                if (bq_charger->update_status)
                        bq_charger->update_status
                                (bq_charger->status, 2);
-       } else if ((val & BQ2419x_VBUS_STAT) == BQ2419x_VBUS_AC) {
+       } else {
                bq_charger->status = 1;
                bq_charger->ac_online = 1;
-               bq_charger->in_current_limit = max_uA/1000;
                ret = bq2419x_init(bq_charger);
                if (ret < 0)
                        goto error;
@@ -226,220 +293,521 @@ error:
 }
 
 static struct regulator_ops bq2419x_tegra_regulator_ops = {
-       .set_current_limit = bq2419x_enable_charger,
+       .set_current_limit = bq2419x_set_charging_current,
 };
 
-static void bq2419x_charger_shutdown(struct platform_device *pdev)
+static int bq2419x_reset_wdt(struct bq2419x_chip *bq2419x)
 {
-       struct bq2419x_charger *charger = platform_get_drvdata(pdev);
+       int ret;
+       unsigned int reg01;
+
+       dev_info(bq2419x->dev, "%s() resetting BQWDT\n", __func__);
+       ret = regmap_read(bq2419x->regmap, BQ2419X_PWR_ON_REG, &reg01);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "PWR_ON_REG read failed: %d\n", ret);
+               return ret;
+       }
+
+       reg01 |= BIT(6);
 
-       mutex_lock(&charger->mutex);
-       charger->shutdown_complete = 1;
-       mutex_unlock(&charger->mutex);
+       /* Write two times to make sure reset WDT */
+       ret = regmap_write(bq2419x->regmap, BQ2419X_PWR_ON_REG, reg01);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "PWR_ON_REG write failed: %d\n", ret);
+               return ret;
+       }
+       ret = regmap_write(bq2419x->regmap, BQ2419X_PWR_ON_REG, reg01);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "PWR_ON_REG write failed: %d\n", ret);
+               return ret;
+       }
+       return ret;
 }
 
-static int __devinit bq2419x_charger_probe(struct platform_device *pdev)
+static int bq2419x_watchdog_set_timeout(struct bq2419x_chip *bq2419x,
+                       int timeout)
 {
-       struct bq2419x_platform_data *chip_pdata;
-       struct bq2419x_charger_platform_data *bcharger_pdata = NULL;
-       struct bq2419x_charger *charger;
        int ret;
-       u32 val;
-
-       chip_pdata = dev_get_platdata(pdev->dev.parent);
-       if (chip_pdata)
-               bcharger_pdata = chip_pdata->bcharger_pdata;
+       unsigned int val;
 
-       if (!bcharger_pdata) {
-               dev_err(&pdev->dev, "No Platform data");
-               return -EIO;
+       /* Disable WDT first */
+       ret = regmap_update_bits(bq2419x->regmap, BQ2419X_TIME_CTRL_REG,
+                                       BQ2419X_WD_MASK, BQ2419X_WD_DISABLE);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "TIME_CTRL_REG update failed %d\n", ret);
+               return ret;
        }
 
-       charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
-       if (!charger) {
-               dev_err(&pdev->dev, "Memory alloc failed\n");
-               return -ENOMEM;
+       if (!timeout)
+               return ret;
+
+       if (timeout <= 60) {
+               val = BQ2419X_WD_40ms;
+               bq2419x->wdt_refresh_timeout = 25;
+       } else if (timeout <= 120) {
+               val = BQ2419X_WD_80ms;
+               bq2419x->wdt_refresh_timeout = 50;
+       } else {
+               val = BQ2419X_WD_160ms;
+               bq2419x->wdt_refresh_timeout = 125;
        }
 
-       charger->chip = dev_get_drvdata(pdev->dev.parent);
-       charger->dev = &pdev->dev;
-       charger->use_usb = bcharger_pdata->use_usb;
-       charger->use_mains = bcharger_pdata->use_mains;
-       charger->gpio_status = bcharger_pdata->gpio_status;
-       charger->gpio_interrupt = bcharger_pdata->gpio_interrupt;
-       charger->update_status = bcharger_pdata->update_status;
-       charger->shutdown_complete = 0;
-       bq_charger = charger;
-       platform_set_drvdata(pdev, charger);
-       mutex_init(&charger->mutex);
-       mutex_init(&charger->chrg_mutex);
-
-       ret = regmap_read(charger->chip->regmap, BQ2419X_REVISION_REG, &val);
+       ret = regmap_update_bits(bq2419x->regmap, BQ2419X_TIME_CTRL_REG,
+                                       BQ2419X_WD_MASK, val);
        if (ret < 0) {
-               dev_err(charger->dev, "error reading reg: 0x%x, err = %d\n",
-                                       BQ2419X_REVISION_REG, ret);
+               dev_err(bq2419x->dev, "TIME_CTRL_REG update failed %d\n", ret);
                return ret;
        }
+       return ret;
+}
 
-       if ((val & BQ24190_IC_VER) == BQ24190_IC_VER)
-               dev_info(charger->dev, "chip type BQ24190 detected\n");
-       else if ((val & BQ24192_IC_VER) == BQ24192_IC_VER)
-               dev_info(charger->dev, "chip type BQ2419X/3 detected\n");
-       else if ((val & BQ24192i_IC_VER) == BQ24192i_IC_VER)
-               dev_info(charger->dev, "chip type BQ2419Xi detected\n");
+static void bq2419x_work_thread(struct kthread_work *work)
+{
+       struct bq2419x_chip *bq2419x = container_of(work,
+                       struct bq2419x_chip, bq_wdt_work);
+       int ret;
 
-       charger->gpio_status = bcharger_pdata->gpio_status;
-       charger->gpio_interrupt = bcharger_pdata->gpio_interrupt;
+       for (;;) {
+               if (bq2419x->stop_thread)
+                       return;
 
-       if (gpio_is_valid(charger->gpio_status)) {
-               ret = gpio_request_one(charger->gpio_status,
-                                       GPIOF_IN, "bq2419x-status");
-               if (ret < 0) {
-                       dev_err(charger->dev,
-                               "status gpio request failed, err = %d\n", ret);
-                       return ret;
-               }
+               ret = bq2419x_reset_wdt(bq2419x);
+               if (ret < 0)
+                       dev_err(bq2419x->dev,
+                               "bq2419x_reset_wdt failed: %d\n", ret);
+
+               msleep(bq2419x->wdt_refresh_timeout * 1000);
        }
+}
 
-       /* Configure Charge Current Control to 3A*/
-       ret = regmap_write(charger->chip->regmap, BQ2419X_CHRG_CTRL_REG, 0xC0);
+static irqreturn_t bq2419x_irq(int irq, void *data)
+{
+       struct bq2419x_chip *bq2419x = data;
+       int ret;
+       unsigned int val;
+
+       ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, &val);
        if (ret < 0) {
-               dev_err(charger->dev, "error writing to reg: 0x%x\n",
-                               BQ2419X_CHRG_CTRL_REG);
+               dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret);
                return ret;
        }
 
-       /* Configure Input voltage limit reset to OTP value */
-       ret = regmap_write(charger->chip->regmap, BQ2419X_INPUT_SRC_REG, 0x32);
+       dev_info(bq2419x->dev, "%s() Irq %d status 0x%02x\n",
+               __func__, irq, val);
+
+       if (val & BQ2419x_FAULT_WATCHDOG_FAULT) {
+               dev_err(bq2419x->dev,
+                       "Charging Fault: Watchdog Timer Expired\n");
+               bq2419x_reset_wdt(bq2419x);
+       }
+
+       if (val & BQ2419x_FAULT_BOOST_FAULT)
+               dev_err(bq2419x->dev, "Charging Fault: VBUS Overloaded\n");
+
+       switch (val & BQ2419x_FAULT_CHRG_FAULT_MASK) {
+       case BQ2419x_FAULT_CHRG_INPUT:
+               dev_err(bq2419x->dev, "Charging Fault: "
+                               "Input Fault (VBUS OVP or VBAT<VBUS<3.8V)\n");
+               break;
+       case BQ2419x_FAULT_CHRG_THERMAL:
+               dev_err(bq2419x->dev, "Charging Fault: Thermal shutdown\n");
+               break;
+       case BQ2419x_FAULT_CHRG_SAFTY:
+               dev_err(bq2419x->dev,
+                       "Charging Fault: Safety timer expiration\n");
+               break;
+       default:
+               break;
+       }
+
+       if (val & BQ2419x_FAULT_NTC_FAULT)
+               dev_err(bq2419x->dev, "Charging Fault: NTC fault %d\n",
+                               val & BQ2419x_FAULT_NTC_FAULT);
+
+       ret = regmap_read(bq2419x->regmap, BQ2419X_SYS_STAT_REG, &val);
        if (ret < 0) {
-               dev_err(charger->dev, "error writing to reg: 0x%x\n",
-                               BQ2419X_CHRG_CTRL_REG);
+               dev_err(bq2419x->dev, "SYS_STAT_REG read failed %d\n", ret);
                return ret;
        }
 
-       charger->reg_desc.name  = "vbus_charger";
-       charger->reg_desc.ops   = &bq2419x_tegra_regulator_ops;
-       charger->reg_desc.type  = REGULATOR_CURRENT;
-       charger->reg_desc.id    = bcharger_pdata->regulator_id;
-       charger->reg_desc.type  = REGULATOR_CURRENT;
-       charger->reg_desc.owner = THIS_MODULE;
+       if ((val & BQ2419x_CHRG_STATE_MASK) == BQ2419x_CHRG_STATE_CHARGE_DONE)
+               dev_info(bq2419x->dev, "Charging completed\n");
+
+       return IRQ_HANDLED;
+}
+
+static int bq2419x_init_charger_regulator(struct bq2419x_chip *bq2419x,
+               struct bq2419x_platform_data *pdata)
+{
+       int ret = 0;
 
-       charger->reg_init_data.supply_regulator         = NULL;
-       charger->reg_init_data.num_consumer_supplies    =
-                               bcharger_pdata->num_consumer_supplies;
+       if (!pdata->bcharger_pdata) {
+               dev_err(bq2419x->dev, "No charger platform data\n");
+               return 0;
+       }
 
-       charger->reg_init_data.regulator_init           = NULL;
-       charger->reg_init_data.consumer_supplies        =
-                                       bcharger_pdata->consumer_supplies;
-       charger->reg_init_data.driver_data              = charger;
-       charger->reg_init_data.constraints.name         = "vbus_charger";
-       charger->reg_init_data.constraints.min_uA       = 0;
-       charger->reg_init_data.constraints.max_uA       =
-                               bcharger_pdata->max_charge_current_mA * 1000;
+       bq2419x->chg_reg_desc.name  = "bq2419x-charger";
+       bq2419x->chg_reg_desc.ops   = &bq2419x_tegra_regulator_ops;
+       bq2419x->chg_reg_desc.type  = REGULATOR_CURRENT;
+       bq2419x->chg_reg_desc.owner = THIS_MODULE;
+
+       bq2419x->chg_reg_init_data.supply_regulator     = NULL;
+       bq2419x->chg_reg_init_data.regulator_init       = NULL;
+       bq2419x->chg_reg_init_data.num_consumer_supplies =
+                               pdata->bcharger_pdata->num_consumer_supplies;
+       bq2419x->chg_reg_init_data.consumer_supplies    =
+                               pdata->bcharger_pdata->consumer_supplies;
+       bq2419x->chg_reg_init_data.driver_data          = bq2419x;
+       bq2419x->chg_reg_init_data.constraints.name     = "bq2419x-charger";
+       bq2419x->chg_reg_init_data.constraints.min_uA   = 0;
+       bq2419x->chg_reg_init_data.constraints.max_uA   =
+                       pdata->bcharger_pdata->max_charge_current_mA * 1000;
+
+       bq2419x->chg_reg_init_data.constraints.valid_modes_mask =
+                                               REGULATOR_MODE_NORMAL |
+                                               REGULATOR_MODE_STANDBY;
+
+       bq2419x->chg_reg_init_data.constraints.valid_ops_mask =
+                                               REGULATOR_CHANGE_MODE |
+                                               REGULATOR_CHANGE_STATUS |
+                                               REGULATOR_CHANGE_CURRENT;
+
+       bq2419x->chg_rdev = regulator_register(&bq2419x->chg_reg_desc,
+                               bq2419x->dev, &bq2419x->chg_reg_init_data,
+                               bq2419x, NULL);
+       if (IS_ERR(bq2419x->chg_rdev)) {
+               ret = PTR_ERR(bq2419x->chg_rdev);
+               dev_err(bq2419x->dev,
+                       "vbus-charger regulator register failed %d\n", ret);
+       }
+       return ret;
+}
 
-       charger->reg_init_data.constraints.valid_modes_mask =
+static int bq2419x_init_vbus_regulator(struct bq2419x_chip *bq2419x,
+               struct bq2419x_platform_data *pdata)
+{
+       int ret = 0;
+
+       if (!pdata->vbus_pdata) {
+               dev_err(bq2419x->dev, "No vbus platform data\n");
+               return 0;
+       }
+
+       bq2419x->gpio_otg_iusb = pdata->vbus_pdata->gpio_otg_iusb;
+       bq2419x->vbus_reg_desc.name = "bq2419x-vbus";
+       bq2419x->vbus_reg_desc.ops = &bq2419x_vbus_ops;
+       bq2419x->vbus_reg_desc.type = REGULATOR_VOLTAGE;
+       bq2419x->vbus_reg_desc.owner = THIS_MODULE;
+
+       bq2419x->vbus_reg_init_data.supply_regulator    = NULL;
+       bq2419x->vbus_reg_init_data.regulator_init      = NULL;
+       bq2419x->vbus_reg_init_data.num_consumer_supplies       =
+                               pdata->vbus_pdata->num_consumer_supplies;
+       bq2419x->vbus_reg_init_data.consumer_supplies   =
+                               pdata->vbus_pdata->consumer_supplies;
+       bq2419x->vbus_reg_init_data.driver_data         = bq2419x;
+
+       bq2419x->vbus_reg_init_data.constraints.name    = "bq2419x-vbus";
+       bq2419x->vbus_reg_init_data.constraints.min_uV  = 0;
+       bq2419x->vbus_reg_init_data.constraints.max_uV  = 5000000,
+       bq2419x->vbus_reg_init_data.constraints.valid_modes_mask =
                                        REGULATOR_MODE_NORMAL |
                                        REGULATOR_MODE_STANDBY;
-
-       charger->reg_init_data.constraints.valid_ops_mask =
+       bq2419x->vbus_reg_init_data.constraints.valid_ops_mask =
                                        REGULATOR_CHANGE_MODE |
                                        REGULATOR_CHANGE_STATUS |
-                                       REGULATOR_CHANGE_CURRENT;
-
-       charger->rdev = regulator_register(&charger->reg_desc, charger->dev,
-                                       &charger->reg_init_data, charger, NULL);
-
-       if (IS_ERR(charger->rdev)) {
-               dev_err(&pdev->dev, "failed to register %s\n",
-                               charger->reg_desc.name);
-               ret = PTR_ERR(charger->rdev);
-               goto free_gpio_status;
-       }
-
-       charger->ac_online = 0;
-       charger->usb_online = 0;
-       charger->status = 0;
-       if (charger->use_mains) {
-               charger->ac.name                = "bq2419x-ac";
-               charger->ac.type                = POWER_SUPPLY_TYPE_MAINS;
-               charger->ac.get_property        = bq2419x_ac_get_property;
-               charger->ac.properties          = bq2419x_psy_props;
-               charger->ac.num_properties      = ARRAY_SIZE(bq2419x_psy_props);
-               ret = power_supply_register(&pdev->dev, &charger->ac);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed: power supply register\n");
+                                       REGULATOR_CHANGE_VOLTAGE;
+
+       if (gpio_is_valid(bq2419x->gpio_otg_iusb)) {
+               ret = gpio_request_one(bq2419x->gpio_otg_iusb,
+                               GPIOF_OUT_INIT_LOW, dev_name(bq2419x->dev));
+               if (ret < 0) {
+                       dev_err(bq2419x->dev, "gpio request failed  %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* Register the regulators */
+       bq2419x->vbus_rdev = regulator_register(&bq2419x->vbus_reg_desc,
+                       bq2419x->dev, &bq2419x->vbus_reg_init_data,
+                       bq2419x, NULL);
+       if (IS_ERR(bq2419x->vbus_rdev)) {
+               ret = PTR_ERR(bq2419x->vbus_rdev);
+               dev_err(bq2419x->dev,
+                       "VBUS regulator register failed %d\n", ret);
+               goto scrub;
+       }
+
+       /* Disable the VBUS regulator and enable charging */
+       ret = bq2419x_charger_enable(bq2419x);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "Charging enable failed %d", ret);
+               goto scrub_reg;
+       }
+       return ret;
+
+scrub_reg:
+       regulator_unregister(bq2419x->vbus_rdev);
+       bq2419x->vbus_rdev = NULL;
+scrub:
+       if (gpio_is_valid(bq2419x->gpio_otg_iusb))
+               gpio_free(bq2419x->gpio_otg_iusb);
+       return ret;
+}
+
+static int bq2419x_psy_init(struct bq2419x_chip *bq2419x)
+{
+       int ret = 0;
+
+       bq2419x->ac_online = 0;
+       bq2419x->usb_online = 0;
+       bq2419x->status = 0;
+       if (bq2419x->use_mains) {
+               bq2419x->ac.name                = "bq2419x-ac";
+               bq2419x->ac.type                = POWER_SUPPLY_TYPE_MAINS;
+               bq2419x->ac.get_property        = bq2419x_ac_get_property;
+               bq2419x->ac.properties          = bq2419x_psy_props;
+               bq2419x->ac.num_properties      = ARRAY_SIZE(bq2419x_psy_props);
+               ret = power_supply_register(bq2419x->dev, &bq2419x->ac);
+               if (ret < 0) {
+                       dev_err(bq2419x->dev,
+                               "AC power supply register failed %d\n", ret);
                        return ret;
                }
        }
 
-       if (charger->use_usb) {
-               charger->usb.name               = "bq2419x-usb";
-               charger->usb.type               = POWER_SUPPLY_TYPE_USB;
-               charger->usb.get_property       = bq2419x_usb_get_property;
-               charger->usb.properties         = bq2419x_psy_props;
-               charger->usb.num_properties     = ARRAY_SIZE(bq2419x_psy_props);
-               ret = power_supply_register(&pdev->dev, &charger->usb);
+       if (bq2419x->use_usb) {
+               bq2419x->usb.name               = "bq2419x-usb";
+               bq2419x->usb.type               = POWER_SUPPLY_TYPE_USB;
+               bq2419x->usb.get_property       = bq2419x_usb_get_property;
+               bq2419x->usb.properties         = bq2419x_psy_props;
+               bq2419x->usb.num_properties     = ARRAY_SIZE(bq2419x_psy_props);
+               ret = power_supply_register(bq2419x->dev, &bq2419x->usb);
                if (ret) {
-                       dev_err(&pdev->dev, "failed: power supply register\n");
-                       goto psy_error;
+                       dev_err(bq2419x->dev,
+                               "usb power supply register failed %d\n", ret);
+                       goto scrub;
                }
        }
+       return ret;
+scrub:
+       if (bq2419x->use_mains)
+               power_supply_unregister(&bq2419x->ac);
+       return ret;
+}
+
+static int bq2419x_show_chip_version(struct bq2419x_chip *bq2419x)
+{
+       int ret;
+       unsigned int val;
+
+       ret = regmap_read(bq2419x->regmap, BQ2419X_REVISION_REG, &val);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "REVISION_REG read failed: %d\n", ret);
+               return ret;
+       }
+
+       if ((val & BQ24190_IC_VER) == BQ24190_IC_VER)
+               dev_info(bq2419x->dev, "chip type BQ24190 detected\n");
+       else if ((val & BQ24192_IC_VER) == BQ24192_IC_VER)
+               dev_info(bq2419x->dev, "chip type BQ2419X/3 detected\n");
+       else if ((val & BQ24192i_IC_VER) == BQ24192i_IC_VER)
+               dev_info(bq2419x->dev, "chip type BQ2419Xi detected\n");
+       return 0;
+}
+
+static int bq2419x_charger_init(struct bq2419x_chip *bq2419x)
+{
+       int ret;
+
+       /* Configure Output Current Control to 3A*/
+       ret = regmap_write(bq2419x->regmap, BQ2419X_CHRG_CTRL_REG, 0xC0);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "CHRG_CTRL_REG write failed %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Configure Input voltage limit reset to OTP value,
+        * and charging current to 500mA.
+        */
+       ret = regmap_write(bq2419x->regmap, BQ2419X_INPUT_SRC_REG, 0x32);
+       if (ret < 0)
+               dev_err(bq2419x->dev, "INPUT_SRC_REG write failed %d\n", ret);
+
+       return ret;
+}
+
+static int __devinit bq2419x_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct bq2419x_chip *bq2419x;
+       struct bq2419x_platform_data *pdata;
+       int ret = 0;
+
+       pdata = client->dev.platform_data;
+       if (!pdata) {
+               dev_err(&client->dev, "No Platform data");
+               return -EINVAL;
+       }
+
+       bq2419x = devm_kzalloc(&client->dev, sizeof(*bq2419x), GFP_KERNEL);
+       if (!bq2419x) {
+               dev_err(&client->dev, "Memory allocation failed\n");
+               return -ENOMEM;
+       }
+
+       bq2419x->regmap = devm_regmap_init_i2c(client, &bq2419x_regmap_config);
+       if (IS_ERR(bq2419x->regmap)) {
+               ret = PTR_ERR(bq2419x->regmap);
+               dev_err(&client->dev, "regmap init failed with err %d\n", ret);
+               return ret;
+       }
+
+       bq2419x->dev = &client->dev;
+       bq2419x->use_usb = pdata->bcharger_pdata->use_usb;
+       bq2419x->use_mains =  pdata->bcharger_pdata->use_mains;
+       bq2419x->update_status =  pdata->bcharger_pdata->update_status;
+       bq2419x->wdt_refresh_timeout = 25;
+       i2c_set_clientdata(client, bq2419x);
+       bq2419x->irq = client->irq;
+
+       ret = bq2419x_show_chip_version(bq2419x);
+       if (ret < 0) {
+               dev_err(&client->dev, "version read failed %d\n", ret);
+               return ret;
+       }
+
+       ret = bq2419x_charger_init(bq2419x);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "Charger init failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = bq2419x_watchdog_set_timeout(bq2419x,
+                       pdata->bcharger_pdata->wdt_timeout);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "BQWDT init failed %d\n", ret);
+               return ret;
+       }
+
+       ret = bq2419x_init_charger_regulator(bq2419x, pdata);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "Charger regualtor init failed %d\n", ret);
+               return ret;
+       }
+
+       ret = bq2419x_psy_init(bq2419x);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "Charger power supply init failed %d\n", ret);
+               goto scrub_chg_reg;
+       }
+
+       ret = bq2419x_init_vbus_regulator(bq2419x, pdata);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "VBUS regualtor init failed %d\n", ret);
+               goto scrub_psy;
+       }
+
+
+       init_kthread_worker(&bq2419x->bq_kworker);
+       bq2419x->bq_kworker_task = kthread_run(kthread_worker_fn,
+                               &bq2419x->bq_kworker,
+                               dev_name(bq2419x->dev));
+       if (IS_ERR(bq2419x->bq_kworker_task)) {
+               ret = PTR_ERR(bq2419x->bq_kworker_task);
+               dev_err(&client->dev, "Kworker task creation failed %d\n", ret);
+               goto scrub_vbus_reg;
+       }
+
+       init_kthread_work(&bq2419x->bq_wdt_work, bq2419x_work_thread);
+       sched_setscheduler(bq2419x->bq_kworker_task,
+                       SCHED_FIFO, &bq2419x_param);
+       queue_kthread_work(&bq2419x->bq_kworker, &bq2419x->bq_wdt_work);
+
+       ret = request_threaded_irq(bq2419x->irq, NULL,
+               bq2419x_irq, IRQF_TRIGGER_FALLING,
+                       dev_name(bq2419x->dev), bq2419x);
+       if (ret < 0) {
+               dev_err(bq2419x->dev, "request IRQ %d fail, err = %d\n",
+                               bq2419x->irq, ret);
+               goto scrub_kthread;
+       }
 
        /* enable charging */
-       ret = bq2419x_charger_enable(charger);
+       ret = bq2419x_charger_enable(bq2419x);
        if (ret < 0)
-               goto psy_error1;
+               goto scrub_irq;
+
        return 0;
 
-psy_error1:
-       power_supply_unregister(&charger->usb);
-psy_error:
-       power_supply_unregister(&charger->ac);
-free_gpio_status:
-       if (gpio_is_valid(charger->gpio_status))
-               gpio_free(charger->gpio_status);
-       mutex_destroy(&charger->mutex);
-       mutex_destroy(&charger->chrg_mutex);
+scrub_irq:
+       free_irq(bq2419x->irq, bq2419x);
+scrub_kthread:
+       bq2419x->stop_thread = true;
+       flush_kthread_worker(&bq2419x->bq_kworker);
+       kthread_stop(bq2419x->bq_kworker_task);
+scrub_vbus_reg:
+       regulator_unregister(bq2419x->vbus_rdev);
+scrub_psy:
+       if (bq2419x->use_usb)
+               power_supply_unregister(&bq2419x->usb);
+       if (bq2419x->use_mains)
+               power_supply_unregister(&bq2419x->ac);
+scrub_chg_reg:
+       regulator_unregister(bq2419x->chg_rdev);
        return ret;
 }
 
-static int __devexit bq2419x_charger_remove(struct platform_device *pdev)
+static int __devexit bq2419x_remove(struct i2c_client *client)
 {
-       struct bq2419x_charger *charger = platform_get_drvdata(pdev);
-
-       if (charger->use_mains)
-               power_supply_unregister(&charger->usb);
-       if (charger->use_usb)
-               power_supply_unregister(&charger->ac);
-       if (gpio_is_valid(charger->gpio_status))
-               gpio_free(charger->gpio_status);
-       mutex_destroy(&charger->mutex);
-       mutex_destroy(&charger->chrg_mutex);
+       struct bq2419x_chip *bq2419x = i2c_get_clientdata(client);
+
+       free_irq(bq2419x->irq, bq2419x);
+       bq2419x->stop_thread = true;
+       flush_kthread_worker(&bq2419x->bq_kworker);
+       kthread_stop(bq2419x->bq_kworker_task);
+       regulator_unregister(bq2419x->vbus_rdev);
+       if (bq2419x->use_usb)
+               power_supply_unregister(&bq2419x->usb);
+       if (bq2419x->use_mains)
+               power_supply_unregister(&bq2419x->ac);
+       regulator_unregister(bq2419x->chg_rdev);
        return 0;
 }
 
-static struct platform_driver bq2419x_charger_driver = {
+static const struct i2c_device_id bq2419x_id[] = {
+       {.name = "bq2419x",},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, bq2419x_id);
+
+static struct i2c_driver bq2419x_i2c_driver = {
        .driver = {
-               .name = "bq2419x-battery-charger",
+               .name = "bq2419x",
                .owner = THIS_MODULE,
        },
-       .probe = bq2419x_charger_probe,
-       .shutdown = bq2419x_charger_shutdown,
-       .remove = __devexit_p(bq2419x_charger_probe),
+       .probe = bq2419x_probe,
+       .remove = __devexit_p(bq2419x_remove),
+       .id_table = bq2419x_id,
 };
 
-static int __init bq2419x_charger_init(void)
+static int __init bq2419x_module_init(void)
 {
-       return platform_driver_register(&bq2419x_charger_driver);
+       return i2c_add_driver(&bq2419x_i2c_driver);
 }
-subsys_initcall(bq2419x_charger_init);
+subsys_initcall(bq2419x_module_init);
 
-static void __exit bq2419x_charger_cleanup(void)
+static void __exit bq2419x_cleanup(void)
 {
-       platform_driver_unregister(&bq2419x_charger_driver);
+       i2c_del_driver(&bq2419x_i2c_driver);
 }
-module_exit(bq2419x_charger_cleanup);
+module_exit(bq2419x_cleanup);
 
-MODULE_DESCRIPTION("bq2419x battery charger driver");
+MODULE_DESCRIPTION("BQ24190/BQ24192/BQ24192i/BQ24193 battery charger driver");
 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com");
 MODULE_LICENSE("GPL v2");
diff --git a/include/linux/power/bq2419x-charger.h b/include/linux/power/bq2419x-charger.h
new file mode 100644 (file)
index 0000000..577777e
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * bq2419x-charger.h -- BQ24190/BQ24192/BQ24192i/BQ24193 Charger driver
+ *
+ * Copyright (C) 2012 - 2013 NVIDIA Corporation
+
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ * Author: Syed Rafiuddin <srafiuddin@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_POWER_BQ2419X_CHARGER_H
+#define __LINUX_POWER_BQ2419X_CHARGER_H
+
+
+/* Register definitions */
+#define BQ2419X_INPUT_SRC_REG          0x00
+#define BQ2419X_PWR_ON_REG             0x01
+#define BQ2419X_CHRG_CTRL_REG          0x02
+#define BQ2419X_CHRG_TERM_REG          0x03
+#define BQ2419X_VOLT_CTRL_REG          0x04
+#define BQ2419X_TIME_CTRL_REG          0x05
+#define BQ2419X_THERM_REG              0x06
+#define BQ2419X_MISC_OPER_REG          0x07
+#define BQ2419X_SYS_STAT_REG           0x08
+#define BQ2419X_FAULT_REG              0x09
+#define BQ2419X_REVISION_REG           0x0a
+
+#define BQ24190_IC_VER                 0x40
+#define BQ24192_IC_VER                 0x28
+#define BQ24192i_IC_VER                        0x18
+
+#define BQ2419X_ENABLE_CHARGE_MASK     0x30
+#define BQ2419X_ENABLE_CHARGE          0x10
+#define BQ2419X_ENABLE_VBUS            0x20
+
+#define BQ2419X_REG0                   0x0
+#define BQ2419X_EN_HIZ                 BIT(7)
+
+#define BQ2419X_WD                     0x5
+#define BQ2419X_WD_MASK                        0x30
+#define BQ2419X_WD_DISABLE             0x00
+#define BQ2419X_WD_40ms                        0x10
+#define BQ2419X_WD_80ms                        0x20
+#define BQ2419X_WD_160ms               0x30
+
+#define BQ2419x_VBUS_STAT              0xc0
+#define BQ2419x_VBUS_UNKNOWN           0x00
+#define BQ2419x_VBUS_USB               0x40
+#define BQ2419x_VBUS_AC                        0x80
+
+#define BQ2419x_CHRG_STATE_MASK                        0x30
+#define BQ2419x_CHRG_STATE_NOTCHARGING         0x00
+#define BQ2419x_CHRG_STATE_PRE_CHARGE          0x10
+#define BQ2419x_CHRG_STATE_POST_CHARGE         0x20
+#define BQ2419x_CHRG_STATE_CHARGE_DONE         0x30
+
+#define BQ2419x_FAULT_WATCHDOG_FAULT           BIT(7)
+#define BQ2419x_FAULT_BOOST_FAULT              BIT(6)
+#define BQ2419x_FAULT_CHRG_FAULT_MASK          0x30
+#define BQ2419x_FAULT_CHRG_NORMAL              0x00
+#define BQ2419x_FAULT_CHRG_INPUT               0x10
+#define BQ2419x_FAULT_CHRG_THERMAL             0x20
+#define BQ2419x_FAULT_CHRG_SAFTY               0x30
+
+#define BQ2419x_FAULT_NTC_FAULT                        0x07
+
+#define BQ2419x_CONFIG_MASK            0x7
+#define BQ2419X_MAX_REGS               (BQ2419X_REVISION_REG + 1)
+
+/*
+ * struct bq2419x_vbus_platform_data - bq2419x VBUS platform data.
+ *
+ * @gpio_otg_iusb: GPIO number for OTG/IUSB
+ * @num_consumer_supplies: Number fo consumer for vbus regulators.
+ * @consumer_supplies: List of consumer suppliers.
+ */
+struct bq2419x_vbus_platform_data {
+       int gpio_otg_iusb;
+       int num_consumer_supplies;
+       struct regulator_consumer_supply *consumer_supplies;
+};
+
+/*
+ * struct bq2419x_charger_platform_data - bq2419x charger platform data.
+ */
+struct bq2419x_charger_platform_data {
+       unsigned use_mains:1;
+       unsigned use_usb:1;
+       void (*update_status)(int, int);
+       int (*battery_check)(void);
+
+       int max_charge_volt_mV;
+       int max_charge_current_mA;
+       int charging_term_current_mA;
+       int wdt_timeout;
+       int num_consumer_supplies;
+       struct regulator_consumer_supply *consumer_supplies;
+};
+
+/*
+ * struct bq2419x_platform_data - bq2419x platform data.
+ */
+struct bq2419x_platform_data {
+       struct bq2419x_vbus_platform_data *vbus_pdata;
+       struct bq2419x_charger_platform_data *bcharger_pdata;
+};
+
+#endif /* __LINUX_POWER_BQ2419X_CHARGER_H */