ab8500-fg: Add power cut feature for ab8505 and ab8540
authorLee Jones <lee.jones@linaro.org>
Thu, 31 May 2012 14:16:36 +0000 (16:16 +0200)
committerLee Jones <lee.jones@linaro.org>
Thu, 7 Mar 2013 04:35:36 +0000 (12:35 +0800)
Add support for a power cut feature which allows user to
configure when ab8505 and ab8540 based platforms should shut
down system due to low battery.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/mfd/ab8500-core.c
drivers/power/ab8500_bmdata.c
drivers/power/ab8500_fg.c
include/linux/mfd/abx500.h
include/linux/mfd/abx500/ab8500-bm.h

index c7ff557..f276352 100644 (file)
 #define AB8500_SWITCH_OFF_STATUS       0x00
 
 #define AB8500_TURN_ON_STATUS          0x00
+#define AB8505_TURN_ON_STATUS_2        0x04
 
 #define AB8500_CH_USBCH_STAT1_REG      0x02
 #define VBUS_DET_DBNC100               0x02
@@ -1401,6 +1402,21 @@ static ssize_t show_turn_on_status(struct device *dev,
        return sprintf(buf, "%#x\n", value);
 }
 
+static ssize_t show_turn_on_status_2(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int ret;
+       u8 value;
+       struct ab8500 *ab8500;
+
+       ab8500 = dev_get_drvdata(dev);
+       ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
+               AB8505_TURN_ON_STATUS_2, &value);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%#x\n", (value & 0x1));
+}
+
 static ssize_t show_ab9540_dbbrstn(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -1457,6 +1473,7 @@ exit:
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
 static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL);
 static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
                        show_ab9540_dbbrstn, store_ab9540_dbbrstn);
 
@@ -1467,6 +1484,11 @@ static struct attribute *ab8500_sysfs_entries[] = {
        NULL,
 };
 
+static struct attribute *ab8505_sysfs_entries[] = {
+       &dev_attr_turn_on_status_2.attr,
+       NULL,
+};
+
 static struct attribute *ab9540_sysfs_entries[] = {
        &dev_attr_chip_id.attr,
        &dev_attr_switch_off_status.attr,
@@ -1479,6 +1501,10 @@ static struct attribute_group ab8500_attr_group = {
        .attrs  = ab8500_sysfs_entries,
 };
 
+static struct attribute_group ab8505_attr_group = {
+       .attrs  = ab8505_sysfs_entries,
+};
+
 static struct attribute_group ab9540_attr_group = {
        .attrs  = ab9540_sysfs_entries,
 };
@@ -1719,6 +1745,12 @@ static int ab8500_probe(struct platform_device *pdev)
        else
                ret = sysfs_create_group(&ab8500->dev->kobj,
                                        &ab8500_attr_group);
+
+       if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+                       ab8500->chip_id >= AB8500_CUT2P0)
+               ret = sysfs_create_group(&ab8500->dev->kobj,
+                                        &ab8505_attr_group);
+
        if (ret)
                dev_err(ab8500->dev, "error creating sysfs entries\n");
 
@@ -1735,6 +1767,10 @@ static int ab8500_remove(struct platform_device *pdev)
        else
                sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
 
+       if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+                       ab8500->chip_id >= AB8500_CUT2P0)
+               sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group);
+
        mfd_remove_devices(ab8500->dev);
 
        return 0;
index 7a96c06..e875976 100644 (file)
@@ -407,6 +407,11 @@ static const struct abx500_fg_parameters fg = {
        .battok_raising_th_sel1 = 2860,
        .maint_thres = 95,
        .user_cap_limit = 15,
+       .pcut_enable = 1,
+       .pcut_max_time = 127,
+       .pcut_flag_time = 112,
+       .pcut_max_restart = 15,
+       .pcut_debounce_time = 2,
 };
 
 static const struct abx500_maxim_parameters maxi_params = {
index 25dae4c..92f342b 100644 (file)
@@ -2344,6 +2344,50 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
                dev_err(di->dev, "BattOk init write failed.\n");
                goto out;
        }
+
+       if (((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+                       abx500_get_chip_id(di->dev) >= AB8500_CUT2P0)
+                       || is_ab8540(di->parent)) {
+               ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                       AB8505_RTC_PCUT_MAX_TIME_REG, di->bm->fg_params->pcut_max_time);
+
+               if (ret) {
+                       dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_MAX_TIME_REG\n", __func__);
+                       goto out;
+               };
+
+               ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                       AB8505_RTC_PCUT_FLAG_TIME_REG, di->bm->fg_params->pcut_flag_time);
+
+               if (ret) {
+                       dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_FLAG_TIME_REG\n", __func__);
+                       goto out;
+               };
+
+               ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                       AB8505_RTC_PCUT_RESTART_REG, di->bm->fg_params->pcut_max_restart);
+
+               if (ret) {
+                       dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_RESTART_REG\n", __func__);
+                       goto out;
+               };
+
+               ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                       AB8505_RTC_PCUT_DEBOUNCE_REG, di->bm->fg_params->pcut_debounce_time);
+
+               if (ret) {
+                       dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_DEBOUNCE_REG\n", __func__);
+                       goto out;
+               };
+
+               ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                       AB8505_RTC_PCUT_CTL_STATUS_REG, di->bm->fg_params->pcut_enable);
+
+               if (ret) {
+                       dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_CTL_STATUS_REG\n", __func__);
+                       goto out;
+               };
+       }
 out:
        return ret;
 }
@@ -2546,6 +2590,428 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di)
 
        return ret;
 }
+
+static ssize_t ab8505_powercut_flagtime_read(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+               AB8505_RTC_PCUT_FLAG_TIME_REG, &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_FLAG_TIME_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_flagtime_write(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       int ret;
+       long unsigned reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       reg_value = simple_strtoul(buf, NULL, 10);
+
+       if (reg_value > 0x7F) {
+               dev_err(dev, "Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime\n");
+               goto fail;
+       }
+
+       ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+               AB8505_RTC_PCUT_FLAG_TIME_REG, (u8)reg_value);
+
+       if (ret < 0)
+               dev_err(dev, "Failed to set AB8505_RTC_PCUT_FLAG_TIME_REG\n");
+
+fail:
+       return count;
+}
+
+static ssize_t ab8505_powercut_maxtime_read(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+               AB8505_RTC_PCUT_MAX_TIME_REG, &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_MAX_TIME_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+       return ret;
+
+}
+
+static ssize_t ab8505_powercut_maxtime_write(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       int ret;
+       int reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       reg_value = simple_strtoul(buf, NULL, 10);
+       if (reg_value > 0x7F) {
+               dev_err(dev, "Incorrect parameter, echo 0 (0.0s) - 127 (1.98s) for maxtime\n");
+               goto fail;
+       }
+
+       ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+               AB8505_RTC_PCUT_MAX_TIME_REG, (u8)reg_value);
+
+       if (ret < 0)
+               dev_err(dev, "Failed to set AB8505_RTC_PCUT_MAX_TIME_REG\n");
+
+fail:
+       return count;
+}
+
+static ssize_t ab8505_powercut_restart_read(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+               AB8505_RTC_PCUT_RESTART_REG, &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_RESTART_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF));
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_restart_write(struct device *dev,
+                                            struct device_attribute *attr,
+                                            const char *buf, size_t count)
+{
+       int ret;
+       int reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       reg_value = simple_strtoul(buf, NULL, 10);
+       if (reg_value > 0xF) {
+               dev_err(dev, "Incorrect parameter, echo 0 - 15 for number of restart\n");
+               goto fail;
+       }
+
+       ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_RESTART_REG, (u8)reg_value);
+
+       if (ret < 0)
+               dev_err(dev, "Failed to set AB8505_RTC_PCUT_RESTART_REG\n");
+
+fail:
+       return count;
+
+}
+
+static ssize_t ab8505_powercut_timer_read(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_TIME_REG, &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_TIME_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_restart_counter_read(struct device *dev,
+                                                   struct device_attribute *attr,
+                                                   char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_RESTART_REG, &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_RESTART_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF0) >> 4);
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_read(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_CTL_STATUS_REG, &reg_value);
+
+       if (ret < 0)
+               goto fail;
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x1));
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_write(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       int ret;
+       int reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       reg_value = simple_strtoul(buf, NULL, 10);
+       if (reg_value > 0x1) {
+               dev_err(dev, "Incorrect parameter, echo 0/1 to disable/enable Pcut feature\n");
+               goto fail;
+       }
+
+       ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_CTL_STATUS_REG, (u8)reg_value);
+
+       if (ret < 0)
+               dev_err(dev, "Failed to set AB8505_RTC_PCUT_CTL_STATUS_REG\n");
+
+fail:
+       return count;
+}
+
+static ssize_t ab8505_powercut_flag_read(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_CTL_STATUS_REG,  &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_CTL_STATUS_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x10) >> 4));
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_debounce_read(struct device *dev,
+                                            struct device_attribute *attr,
+                                            char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_DEBOUNCE_REG,  &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_DEBOUNCE_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7));
+
+fail:
+       return ret;
+}
+
+static ssize_t ab8505_powercut_debounce_write(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t count)
+{
+       int ret;
+       int reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       reg_value = simple_strtoul(buf, NULL, 10);
+       if (reg_value > 0x7) {
+               dev_err(dev, "Incorrect parameter, echo 0 to 7 for debounce setting\n");
+               goto fail;
+       }
+
+       ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_DEBOUNCE_REG, (u8)reg_value);
+
+       if (ret < 0)
+               dev_err(dev, "Failed to set AB8505_RTC_PCUT_DEBOUNCE_REG\n");
+
+fail:
+       return count;
+}
+
+static ssize_t ab8505_powercut_enable_status_read(struct device *dev,
+                                                 struct device_attribute *attr,
+                                                 char *buf)
+{
+       int ret;
+       u8 reg_value;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+                                               AB8505_RTC_PCUT_CTL_STATUS_REG, &reg_value);
+
+       if (ret < 0) {
+               dev_err(dev, "Failed to read AB8505_RTC_PCUT_CTL_STATUS_REG\n");
+               goto fail;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x20) >> 5));
+
+fail:
+       return ret;
+}
+
+static struct device_attribute ab8505_fg_sysfs_psy_attrs[] = {
+       __ATTR(powercut_flagtime, (S_IRUGO | S_IWUSR | S_IWGRP),
+               ab8505_powercut_flagtime_read, ab8505_powercut_flagtime_write),
+       __ATTR(powercut_maxtime, (S_IRUGO | S_IWUSR | S_IWGRP),
+               ab8505_powercut_maxtime_read, ab8505_powercut_maxtime_write),
+       __ATTR(powercut_restart_max, (S_IRUGO | S_IWUSR | S_IWGRP),
+               ab8505_powercut_restart_read, ab8505_powercut_restart_write),
+       __ATTR(powercut_timer, S_IRUGO, ab8505_powercut_timer_read, NULL),
+       __ATTR(powercut_restart_counter, S_IRUGO,
+               ab8505_powercut_restart_counter_read, NULL),
+       __ATTR(powercut_enable, (S_IRUGO | S_IWUSR | S_IWGRP),
+               ab8505_powercut_read, ab8505_powercut_write),
+       __ATTR(powercut_flag, S_IRUGO, ab8505_powercut_flag_read, NULL),
+       __ATTR(powercut_debounce_time, (S_IRUGO | S_IWUSR | S_IWGRP),
+               ab8505_powercut_debounce_read, ab8505_powercut_debounce_write),
+       __ATTR(powercut_enable_status, S_IRUGO,
+               ab8505_powercut_enable_status_read, NULL),
+};
+
+static int ab8500_fg_sysfs_psy_create_attrs(struct device *dev)
+{
+       unsigned int i, j;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       if (((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+            abx500_get_chip_id(dev->parent) >= AB8500_CUT2P0)
+           || is_ab8540(di->parent)) {
+               for (j = 0; j < ARRAY_SIZE(ab8505_fg_sysfs_psy_attrs); j++)
+                       if (device_create_file(dev, &ab8505_fg_sysfs_psy_attrs[j]))
+                               goto sysfs_psy_create_attrs_failed_ab8505;
+       }
+       return 0;
+sysfs_psy_create_attrs_failed_ab8505:
+       dev_err(dev, "Failed creating sysfs psy attrs for ab8505.\n");
+       while (j--)
+               device_remove_file(dev, &ab8505_fg_sysfs_psy_attrs[i]);
+
+       return -EIO;
+}
+
+static void ab8500_fg_sysfs_psy_remove_attrs(struct device *dev)
+{
+       unsigned int i;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct ab8500_fg *di;
+
+       di = to_ab8500_fg_device_info(psy);
+
+       if (((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+            abx500_get_chip_id(dev->parent) >= AB8500_CUT2P0)
+           || is_ab8540(di->parent)) {
+               for (i = 0; i < ARRAY_SIZE(ab8505_fg_sysfs_psy_attrs); i++)
+                       (void)device_remove_file(dev, &ab8505_fg_sysfs_psy_attrs[i]);
+       }
+}
+
 /* Exposure to the sysfs interface <<END>> */
 
 #if defined(CONFIG_PM)
@@ -2607,6 +3073,7 @@ static int ab8500_fg_remove(struct platform_device *pdev)
        ab8500_fg_sysfs_exit(di);
 
        flush_scheduled_work();
+       ab8500_fg_sysfs_psy_remove_attrs(di->fg_psy.dev);
        power_supply_unregister(&di->fg_psy);
        platform_set_drvdata(pdev, NULL);
        return ret;
@@ -2772,6 +3239,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
                goto free_irq;
        }
 
+       ret = ab8500_fg_sysfs_psy_create_attrs(di->fg_psy.dev);
+       if (ret) {
+               dev_err(di->dev, "failed to create FG psy\n");
+               ab8500_fg_sysfs_exit(di);
+               goto free_irq;
+       }
+
        /* Calibrate the fg first time */
        di->flags.calibrate = true;
        di->calib_state = AB8500_FG_CALIB_INIT;
index 9ead60b..188aedc 100644 (file)
@@ -89,6 +89,11 @@ struct abx500_fg;
  *                             points.
  * @maint_thres                        This is the threshold where we stop reporting
  *                             battery full while in maintenance, in per cent
+ * @pcut_enable:                       Enable power cut feature in ab8505
+ * @pcut_max_time:             Max time threshold
+ * @pcut_flag_time:            Flagtime threshold
+ * @pcut_max_restart:          Max number of restarts
+ * @pcut_debounce_time:                Sets battery debounce time
  */
 struct abx500_fg_parameters {
        int recovery_sleep_timer;
@@ -106,6 +111,11 @@ struct abx500_fg_parameters {
        int battok_raising_th_sel1;
        int user_cap_limit;
        int maint_thres;
+       bool pcut_enable;
+       u8 pcut_max_time;
+       u8 pcut_flag_time;
+       u8 pcut_max_restart;
+       u8 pcut_debounce_time;
 };
 
 /**
index 8d35bfe..0efbe0e 100644 (file)
 /* Battery type */
 #define BATTERY_UNKNOWN                        00
 
+/* Registers for pcut feature in ab8505 and ab9540 */
+#define AB8505_RTC_PCUT_CTL_STATUS_REG 0x12
+#define AB8505_RTC_PCUT_TIME_REG       0x13
+#define AB8505_RTC_PCUT_MAX_TIME_REG   0x14
+#define AB8505_RTC_PCUT_FLAG_TIME_REG  0x15
+#define AB8505_RTC_PCUT_RESTART_REG    0x16
+#define AB8505_RTC_PCUT_DEBOUNCE_REG   0x17
+
 /**
  * struct res_to_temp - defines one point in a temp to res curve. To
  * be used in battery packs that combines the identification resistor with a
@@ -283,6 +291,11 @@ struct ab8500_fg;
  *                             points.
  * @maint_thres                        This is the threshold where we stop reporting
  *                             battery full while in maintenance, in per cent
+ * @pcut_enable:                       Enable power cut feature in ab8505
+ * @pcut_max_time:             Max time threshold
+ * @pcut_flag_time:            Flagtime threshold
+ * @pcut_max_restart:          Max number of restarts
+ * @pcut_debunce_time: Sets battery debounce time
  */
 struct ab8500_fg_parameters {
        int recovery_sleep_timer;
@@ -299,6 +312,11 @@ struct ab8500_fg_parameters {
        int battok_raising_th_sel1;
        int user_cap_limit;
        int maint_thres;
+       bool pcut_enable;
+       u8 pcut_max_time;
+       u8 pcut_flag_time;
+       u8 pcut_max_restart;
+       u8 pcut_debunce_time;
 };
 
 /**