|
@@ -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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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;
|