Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69594e47 authored by David Keitel's avatar David Keitel
Browse files

power: qpnp-fg: add fuel gauge SRAM interface



The PMI8994 Fuel Gauge has a SRAM interface exposed
via the FG_MEMIF PMIC pheripheral.

A given memory access must first request permission
to read or write to SRAM. This will stop the
fuel gauge's statemachine. The time taken for
a memory access to be granted is up to 1.5 seconds.

Once a memory access has been granted the mem-avail
interrupt is triggered and the memory access can
proceed by configuring the offset within SRAM and
continuing to read or write to the relevant SPMI
buffer registers.

Once a transaction is complete the memory access
request has to be removed to allow the fuel gauge
to continue.

Various configurations are exposed in SRAM such as
the JEITA temperature thresholds. Add support
for the four temperature thresholds to be configured
at boot time and run time through the power supply
framework.

Change-Id: Ic72a9f0dba7fa9fc752f3e34ee49355b7b01513d
Signed-off-by: default avatarDavid Keitel <dkeitel@codeaurora.org>
parent 0a0b25b6
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -24,6 +24,12 @@ Optionally ADC nodes can be added
Parent node required properties:
- compatible : should be "qcom,qpnp-fg" for the FG driver.

Parent node optional properties:
- qcom,warm-bat-decidegc:		Warm battery temperature in decidegC.
- qcom,cool-bat-decidegc:		Cool battery temperature in decidegC.
- qcom,hot-bat-decidegc:		Hot battery temperature in decidegC.
- qcom,cold-bat-decidegc:		Cold battery temperature in decidegC.

qcom,fg-soc node required properties:
- reg : offset and length of the PMIC peripheral register map.
- interrupts : the interrupt mappings.
@@ -40,6 +46,15 @@ qcom,fg-soc node required properties:
		6: sw-fallbk-ocv
		7: sw-fallbk-new-battrt-sts

qcom,fg-memif node required properties:
- reg : offset and length of the PMIC peripheral register map.
- interrupts : the interrupt mappings.
		The format should be
		<slave-id peripheral-id interrupt-number>.
- interrupt-names : names for the mapped fg adc interrupts
		The following interrupts are required:
		0: mem-avail

Example:
pmi8994_fg: qcom,fg {
	spmi-dev-container;
@@ -77,4 +92,13 @@ pmi8994_fg: qcom,fg {
	qcom,fg-adc-ibat@4255 {
		reg = <0x4255 0x1>;
	};

	qcom,fg-memif@4400 {
		reg = <0x4400 0x100>;
		interrupts =	<0x2 0x44 0x0>,
				<0x2 0x44 0x1>;

		interrupt-names =	"mem-avail",
					"data-rcvry-sug";
	};
};
+10 −0
Original line number Diff line number Diff line
@@ -274,6 +274,16 @@
			qcom,fg-adc-ibat@4255 {
				reg = <0x4255 0x1>;
			};

			qcom,fg-memif@4400 {
				status = "okay";
				reg = <0x4400 0x100>;
				interrupts =	<0x2 0x44 0x0>,
						<0x2 0x44 0x1>;

				interrupt-names =	"mem-avail",
							"data-rcvry-sug";
			};
		};
	};

+510 −23
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#define pr_fmt(fmt)	"FG: %s: " fmt, __func__

#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/err.h>
@@ -25,10 +26,30 @@
#include <linux/power_supply.h>

/* Register offsets */

/* Interrupt offsets */
#define INT_RT_STS(base)			(base + 0x10)

/* SPMI Register offsets */
#define SOC_MONOTONIC_SOC	0x09
#define MEM_INTF_CFG		0x40
#define MEM_INTF_CTL		0x41
#define MEM_INTF_ADDR_LSB	0x42
#define MEM_INTF_ADDR_MSB	0x43
#define MEM_INTF_WR_DATA0	0x48
#define MEM_INTF_WR_DATA1	0x49
#define MEM_INTF_WR_DATA2	0x4A
#define MEM_INTF_WR_DATA3	0x4B
#define MEM_INTF_RD_DATA0	0x4C
#define MEM_INTF_RD_DATA1	0x4D
#define MEM_INTF_RD_DATA2	0x4E
#define MEM_INTF_RD_DATA3	0x4F

#define REG_OFFSET_PERP_SUBTYPE	0x05

/* RAM register offsets */
#define RAM_OFFSET		0x400

/* Bit/Mask definitions */
#define FULL_PERCENT		0xFF
#define MAX_TRIES_SOC		5
@@ -43,6 +64,52 @@
#define FG_MEMIF		0xC

#define QPNP_FG_DEV_NAME "qcom,qpnp-fg"
#define MEM_IF_TIMEOUT_MS	2200

/* Debug Flag Definitions */
enum {
	FG_SPMI_DEBUG_WRITES		= BIT(0), /* Show SPMI writes */
	FG_SPMI_DEBUG_READS		= BIT(1), /* Show SPMI reads */
	FG_IRQS				= BIT(2), /* Show interrupts */
	FG_MEM_DEBUG_WRITES		= BIT(3), /* Show SRAM writes */
	FG_MEM_DEBUG_READS		= BIT(4), /* Show SRAM reads */
	FG_POWER_SUPPLY			= BIT(5), /* Show POWER_SUPPLY */
};

struct fg_mem_setting {
	u16	address;
	u8	offset;
	int	value;
};

/* FG_MEMIF setting index */
enum fg_mem_setting_index {
	FG_MEM_JEITA_SOFT_COLD,
	FG_MEM_JEITA_SOFT_HOT,
	FG_MEM_JEITA_HARD_COLD,
	FG_MEM_JEITA_HARD_HOT,
	FG_MEM_SETTING_MAX,
};

#define SETTING(_idx, _address, _offset, _value)	\
	[FG_MEM_##_idx] = {				\
		.address = _address,			\
		.offset = _offset,			\
		.value = _value,			\
	}						\

static struct fg_mem_setting settings[FG_MEM_SETTING_MAX] = {
	/*       ID                    Address, Offset, Value*/
	SETTING(JEITA_SOFT_COLD,       0x454,   0,      100),
	SETTING(JEITA_SOFT_HOT,        0x454,   1,      400),
	SETTING(JEITA_HARD_COLD,       0x454,   2,      50),
	SETTING(JEITA_HARD_HOT,        0x454,   3,      450),
};

static int fg_debug_mask;
module_param_named(
	debug_mask, fg_debug_mask, int, S_IRUSR | S_IWUSR
);

struct fg_irq {
	int			irq;
@@ -81,7 +148,6 @@ enum fg_mem_if_irq {

struct fg_chip {
	struct device		*dev;
	struct dentry		*dent;
	struct spmi_device	*spmi;
	u16			soc_base;
	u16			batt_base;
@@ -91,7 +157,9 @@ struct fg_chip {
	struct fg_irq		soc_irq[FG_SOC_IRQ_COUNT];
	struct fg_irq		batt_irq[FG_BATT_IRQ_COUNT];
	struct fg_irq		mem_irq[FG_MEM_IF_IRQ_COUNT];
	struct fg_mem_if_chip	*memif;
	struct delayed_work	update_jeita_setting;
	struct mutex		rw_lock;
	struct completion	sram_access;
	struct power_supply	bms_psy;
};

@@ -104,24 +172,254 @@ static char *fg_supplicants[] = {
	"battery"
};

static int fg_read(struct fg_chip *chip, u8 *val, u16 base, int count)
#define DEBUG_PRINT_BUFFER_SIZE 64
static void fill_string(char *str, size_t str_len, u8 *buf, int buf_len)
{
	int pos = 0;
	int i;

	for (i = 0; i < buf_len; i++) {
		pos += scnprintf(str + pos, str_len - pos, "0x%02X", buf[i]);
		if (i < buf_len - 1)
			pos += scnprintf(str + pos, str_len - pos, ", ");
	}
}

static int fg_write(struct fg_chip *chip, u8 *val, u16 addr, int len)
{
	int rc = 0;
	struct spmi_device *spmi = chip->spmi;
	char str[DEBUG_PRINT_BUFFER_SIZE];

	if ((addr & 0xff00) == 0) {
		pr_err("addr cannot be zero base=0x%02x sid=0x%02x rc=%d\n",
			addr, spmi->sid, rc);
		return -EINVAL;
	}

	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, len);
	if (rc) {
		pr_err("write failed addr=0x%02x sid=0x%02x rc=%d\n",
			addr, spmi->sid, rc);
		return rc;
	}

	if (!rc && (fg_debug_mask & FG_SPMI_DEBUG_WRITES)) {
		str[0] = '\0';
		fill_string(str, DEBUG_PRINT_BUFFER_SIZE, val, len);
		pr_info("write(0x%04X), sid=%d, len=%d; %s\n",
			addr, spmi->sid, len, str);
	}

	return rc;
}

static int fg_read(struct fg_chip *chip, u8 *val, u16 addr, int len)
{
	int rc = 0;
	struct spmi_device *spmi = chip->spmi;
	char str[DEBUG_PRINT_BUFFER_SIZE];

	if (base == 0) {
	if ((addr & 0xff00) == 0) {
		pr_err("base cannot be zero base=0x%02x sid=0x%02x rc=%d\n",
			base, spmi->sid, rc);
			addr, spmi->sid, rc);
		return -EINVAL;
	}

	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, val, len);
	if (rc) {
		pr_err("SPMI read failed base=0x%02x sid=0x%02x rc=%d\n", base,
		pr_err("SPMI read failed base=0x%02x sid=0x%02x rc=%d\n", addr,
				spmi->sid, rc);
		return rc;
	}

	if (!rc && (fg_debug_mask & FG_SPMI_DEBUG_READS)) {
		str[0] = '\0';
		fill_string(str, DEBUG_PRINT_BUFFER_SIZE, val, len);
		pr_info("read(0x%04x), sid=%d, len=%d; %s\n",
			addr, spmi->sid, len, str);
	}

	return rc;
}

static int fg_masked_write(struct fg_chip *chip, u16 addr,
		u8 mask, u8 val, int len)
{
	int rc;
	u8 reg;

	rc = fg_read(chip, &reg, addr, len);
	if (rc) {
		pr_err("spmi read failed: addr=%03X, rc=%d\n", addr, rc);
		return rc;
	}
	pr_debug("addr = 0x%x read 0x%x\n", addr, reg);

	reg &= ~mask;
	reg |= val & mask;

	pr_debug("Writing 0x%x\n", reg);

	rc = fg_write(chip, &reg, addr, len);
	if (rc) {
		pr_err("spmi write failed: addr=%03X, rc=%d\n", addr, rc);
		return rc;
	}

	return rc;
}

static inline bool fg_check_sram_access(struct fg_chip *chip)
{
	int rc;
	u8 mem_if_sts;

	rc = fg_read(chip, &mem_if_sts, INT_RT_STS(chip->mem_base), 1);
	if (rc) {
		pr_err("failed to read mem status rc=%d\n", rc);
		return 0;
	}

	return !!(mem_if_sts & BIT(FG_MEM_AVAIL));
}

#define RIF_MEM_ACCESS_REQ	BIT(7)
#define INTF_CTL_BURST		BIT(7)
#define INTF_CTL_WR_EN		BIT(6)
static int fg_config_access(struct fg_chip *chip, bool write,
		bool burst)
{
	int rc;
	u8 intf_ctl = 0;

	intf_ctl = (write ? INTF_CTL_WR_EN : 0) | (burst ? INTF_CTL_BURST : 0);

	rc = fg_write(chip, &intf_ctl, chip->mem_base + MEM_INTF_CTL, 1);
	if (rc) {
		pr_err("failed to set mem access bit\n");
		return -EIO;
	}

	return rc;
}

static int fg_req_and_wait_access(struct fg_chip *chip, int timeout)
{
	int rc = 0, ret = 0;
	bool tried_again = false;

	if (!fg_check_sram_access(chip)) {
		rc = fg_masked_write(chip, chip->mem_base + MEM_INTF_CFG,
				RIF_MEM_ACCESS_REQ, RIF_MEM_ACCESS_REQ, 1);
		if (rc) {
			pr_err("failed to set mem access bit\n");
			return -EIO;
		}
	}

wait:
	/* Wait for MEM_AVAIL IRQ. */
	ret = wait_for_completion_interruptible_timeout(&chip->sram_access,
			msecs_to_jiffies(timeout));
	/* If we were interrupted wait again one more time. */
	if (ret == -ERESTARTSYS && !tried_again) {
		tried_again = true;
		goto wait;
	} else if (ret <= 0) {
		rc = -ETIMEDOUT;
		pr_err("transaction timed out rc=%d\n", rc);
		return rc;
	}

	return rc;
}

static int fg_set_ram_addr(struct fg_chip *chip, u16 *address)
{
	int rc;

	rc = fg_write(chip, (u8 *) address,
			chip->mem_base + MEM_INTF_ADDR_LSB, 2);
	if (rc) {
		pr_err("spmi write failed: addr=%03X, rc=%d\n",
				chip->mem_base + MEM_INTF_ADDR_LSB, rc);
		return rc;
	}

	return rc;
}

static int fg_mem_write(struct fg_chip *chip, u8 *val, u16 address,
		unsigned int len, unsigned int offset, bool keep_access)
{
	int rc = 0;
	u8 *wr_data = val;

	if (address < RAM_OFFSET)
		return -EINVAL;

	if (offset > 3)
		return -EINVAL;

	if (!fg_check_sram_access(chip)) {
		rc = fg_req_and_wait_access(chip, MEM_IF_TIMEOUT_MS);
		if (rc)
			return rc;
	}

	mutex_lock(&chip->rw_lock);
	rc = fg_config_access(chip, 1, (len > 4));
	if (rc)
		goto out;

	rc = fg_set_ram_addr(chip, &address);
	if (rc)
		goto out;

	if (fg_debug_mask & FG_MEM_DEBUG_WRITES)
		pr_info("length %d addr=%02X\n", len, address);

	while (len > 0) {
		if (offset)
			rc = fg_write(chip, wr_data,
				chip->mem_base + MEM_INTF_WR_DATA0 + offset,
				(len > 4) ? 4 : len);
		else
			rc = fg_write(chip, wr_data,
				chip->mem_base + MEM_INTF_WR_DATA0,
				(len > 4) ? 4 : len);
		if (rc) {
			pr_err("spmi read failed: addr=%03x, rc=%d\n",
				chip->mem_base + MEM_INTF_RD_DATA0, rc);
			goto out;
		}
		if (offset) {
			wr_data += 4-offset;
			if (len >= 4)
				len -= 4-offset;
			else
				len = 0;
		} else {
			wr_data += 4;
			if (len >= 4)
				len -= 4;
			else
				len = 0;
		}
	}

	if (!keep_access) {
		rc = fg_masked_write(chip, chip->mem_base + MEM_INTF_CFG,
				RIF_MEM_ACCESS_REQ, 0, 1);
		if (rc) {
			pr_err("failed to set mem access bit\n");
			rc = -EIO;
		}
	}

out:
	mutex_unlock(&chip->rw_lock);
	return 0;
}

@@ -153,13 +451,14 @@ static int get_prop_capacity(struct fg_chip *chip)
	if (cap[0] > 0)
		capacity = (cap[0] * 100 / FULL_PERCENT);

	pr_debug("capacity: %d, raw: 0x%02x\n", capacity, cap[0]);
	if (fg_debug_mask & FG_POWER_SUPPLY)
		pr_info("capacity: %d, raw: 0x%02x\n", capacity, cap[0]);
	return capacity;
}

static int get_prop_current_now(struct fg_chip *chip)
{
	u8 ibat_ma;
	s8 ibat_ma;
	int rc, current_now_ua;

	if (!chip->ibat_adc_addr)
@@ -173,18 +472,16 @@ static int get_prop_current_now(struct fg_chip *chip)
	}

	/* convert to uA */
	current_now_ua = MA_MV_BIT_RES * (ibat_ma & IBAT_VBAT_MASK) * 1000;

	if (ibat_ma & MSB_SIGN)
		current_now_ua *= -1;
	current_now_ua = MA_MV_BIT_RES * ibat_ma * 1000;

	pr_debug("current %d uA\n", current_now_ua);
	if (fg_debug_mask & FG_POWER_SUPPLY)
		pr_info("current %d uA\n", current_now_ua);
	return current_now_ua;
}

static int get_prop_voltage_now(struct fg_chip *chip)
{
	u8 vbat_mv;
	s8 vbat_mv;
	int rc, voltage_now_uv;

	if (!chip->vbat_adc_addr)
@@ -198,20 +495,65 @@ static int get_prop_voltage_now(struct fg_chip *chip)
	}

	/* convert to uV */
	voltage_now_uv = MA_MV_BIT_RES * (vbat_mv & IBAT_VBAT_MASK) * 1000;
	voltage_now_uv = MA_MV_BIT_RES * vbat_mv * 1000;

	if (vbat_mv & MSB_SIGN)
		voltage_now_uv *= -1;

	pr_debug("voltage %d uV\n", voltage_now_uv);
	if (fg_debug_mask & FG_POWER_SUPPLY)
		pr_info("voltage %d uV\n", voltage_now_uv);

	return voltage_now_uv;
}

#define MIN_TEMP_DEGC	-300
#define MAX_TEMP_DEGC	970
static int get_prop_jeita_temp(struct fg_chip *chip, unsigned int type)
{
	return settings[type].value;
}

static int set_prop_jeita_temp(struct fg_chip *chip,
				unsigned int type, int decidegc)
{
	int rc = 0;

	pr_debug("addr 0x%02X, offset %d temp%d\n", settings[type].address,
			settings[type].offset, decidegc);

	settings[type].value = decidegc;

	cancel_delayed_work_sync(
		&chip->update_jeita_setting);
	schedule_delayed_work(
		&chip->update_jeita_setting, 0);

	return rc;
}

static void update_jeita_setting(struct work_struct *work)
{
	struct fg_chip *chip = container_of(work,
				struct fg_chip,
				update_jeita_setting.work);
	u8 reg[4];
	int i, rc;

	for (i = 0; i < 4; i++)
		reg[i] = (settings[JEITA_SOFT_COLD + i].value / 10) + 30;

	rc = fg_mem_write(chip, reg, settings[JEITA_SOFT_COLD].address, 4,
			settings[JEITA_SOFT_COLD].offset, 0);
	if (rc)
		pr_err("failed to update JEITA setting rc=%d\n", rc);
}

static enum power_supply_property fg_power_props[] = {
	POWER_SUPPLY_PROP_CAPACITY,
	POWER_SUPPLY_PROP_CURRENT_NOW,
	POWER_SUPPLY_PROP_VOLTAGE_NOW,
	POWER_SUPPLY_PROP_COOL_TEMP,
	POWER_SUPPLY_PROP_WARM_TEMP,
};

static int fg_power_get_property(struct power_supply *psy,
@@ -230,6 +572,12 @@ static int fg_power_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		val->intval = get_prop_voltage_now(chip);
		break;
	case POWER_SUPPLY_PROP_COOL_TEMP:
		val->intval = get_prop_jeita_temp(chip, FG_MEM_JEITA_SOFT_COLD);
		break;
	case POWER_SUPPLY_PROP_WARM_TEMP:
		val->intval = get_prop_jeita_temp(chip, FG_MEM_JEITA_SOFT_HOT);
		break;
	default:
		return -EINVAL;
	}
@@ -237,14 +585,110 @@ static int fg_power_get_property(struct power_supply *psy,
	return 0;
}

static int fg_power_set_property(struct power_supply *psy,
				  enum power_supply_property psp,
				  const union power_supply_propval *val)
{
	struct fg_chip *chip = container_of(psy, struct fg_chip, bms_psy);
	int rc = 0;

	switch (psp) {
	case POWER_SUPPLY_PROP_COOL_TEMP:
		rc = set_prop_jeita_temp(chip,
				FG_MEM_JEITA_SOFT_COLD, val->intval);
		break;
	case POWER_SUPPLY_PROP_WARM_TEMP:
		rc = set_prop_jeita_temp(chip,
				FG_MEM_JEITA_SOFT_HOT, val->intval);
		break;
	default:
		return -EINVAL;
	};

	return rc;
};

static int fg_property_is_writeable(struct power_supply *psy,
						enum power_supply_property psp)
{
	switch (psp) {
	case POWER_SUPPLY_PROP_COOL_TEMP:
	case POWER_SUPPLY_PROP_WARM_TEMP:
		return 1;
	default:
		break;
	}

	return 0;
}

static irqreturn_t fg_mem_avail_irq_handler(int irq, void *_chip)
{
	struct fg_chip *chip = _chip;
	u8 mem_if_sts;
	int rc;

	rc = fg_read(chip, &mem_if_sts, INT_RT_STS(chip->mem_base), 1);
	if (rc) {
		pr_err("failed to read mem status rc=%d\n", rc);
		return 0;
	}

	if (fg_check_sram_access(chip)) {
		if (fg_debug_mask & FG_IRQS)
			pr_info("sram access granted\n");
		complete_all(&chip->sram_access);
	} else {
		if (fg_debug_mask & FG_IRQS)
			pr_info("sram access revoked\n");
		INIT_COMPLETION(chip->sram_access);
	}

	if (!rc && (fg_debug_mask & FG_IRQS))
		pr_info("mem_if sts 0x%02x\n", mem_if_sts);

	return IRQ_HANDLED;
}

static irqreturn_t fg_soc_irq_handler(int irq, void *_chip)
{
	struct fg_chip *chip = _chip;

	if (fg_debug_mask & FG_IRQS)
		pr_info("triggered\n");

	power_supply_changed(&chip->bms_psy);
	return IRQ_HANDLED;
}

#define OF_READ_SETTING(type, qpnp_dt_property, retval, optional)	\
do {									\
	if (retval)							\
		break;							\
									\
	retval = of_property_read_u32(chip->spmi->dev.of_node,		\
					"qcom," qpnp_dt_property,	\
					&settings[type].value);		\
									\
	if ((retval == -EINVAL) && optional)				\
		retval = 0;						\
	else if (retval)						\
		pr_err("Error reading " #qpnp_dt_property		\
				" property rc = %d\n", rc);		\
} while (0)

static int fg_of_init(struct fg_chip *chip)
{
	int rc = 0;

	OF_READ_SETTING(FG_MEM_JEITA_SOFT_HOT, "warm-bat-decidegc", rc, 1);
	OF_READ_SETTING(FG_MEM_JEITA_SOFT_COLD, "cool-bat-decidegc", rc, 1);
	OF_READ_SETTING(FG_MEM_JEITA_HARD_HOT, "hot-bat-decidegc", rc, 1);
	OF_READ_SETTING(FG_MEM_JEITA_HARD_COLD, "cold-bat-decidegc", rc, 1);

	return rc;
}

static int fg_init_irqs(struct fg_chip *chip)
{
	int rc = 0;
@@ -331,6 +775,24 @@ static int fg_init_irqs(struct fg_chip *chip)
			enable_irq_wake(chip->soc_irq[EMPTY_SOC].irq);
			break;
		case FG_MEMIF:
			chip->mem_irq[FG_MEM_AVAIL].irq = spmi_get_irq_byname(
					chip->spmi, spmi_resource, "mem-avail");
			if (chip->mem_irq[FG_MEM_AVAIL].irq < 0) {
				pr_err("Unable to get mem-avail irq\n");
				return rc;
			}
			rc |= devm_request_irq(chip->dev,
					chip->mem_irq[FG_MEM_AVAIL].irq,
					fg_mem_avail_irq_handler,
					IRQF_TRIGGER_RISING |
					IRQF_TRIGGER_FALLING,
					"mem-avail", chip);
			if (rc < 0) {
				pr_err("Can't request %d mem-avail: %d\n",
					chip->mem_irq[FG_MEM_AVAIL].irq, rc);
				return rc;
			}
			break;
		case FG_BATT:
		case FG_ADC:
			break;
@@ -347,6 +809,8 @@ static int fg_remove(struct spmi_device *spmi)
{
	struct fg_chip *chip = dev_get_drvdata(&spmi->dev);

	mutex_destroy(&chip->rw_lock);
	cancel_delayed_work_sync(&chip->update_jeita_setting);
	power_supply_unregister(&chip->bms_psy);
	dev_set_drvdata(&spmi->dev, NULL);
	return 0;
@@ -354,7 +818,7 @@ static int fg_remove(struct spmi_device *spmi)

static int fg_probe(struct spmi_device *spmi)
{
	struct device *dev = &spmi->dev;
	struct device *dev = &(spmi->dev);
	struct fg_chip *chip;
	struct spmi_resource *spmi_resource;
	struct resource *resource;
@@ -366,8 +830,13 @@ static int fg_probe(struct spmi_device *spmi)
		return -ENODEV;
	}

	if (!spmi) {
		pr_err("no valid spmi pointer\n");
		return -ENODEV;
	}

	chip = devm_kzalloc(dev, sizeof(struct fg_chip), GFP_KERNEL);
	if (!chip) {
	if (chip == NULL) {
		pr_err("Can't allocate fg_chip\n");
		return -ENOMEM;
	}
@@ -375,11 +844,22 @@ static int fg_probe(struct spmi_device *spmi)
	chip->spmi = spmi;
	chip->dev = &(spmi->dev);

	mutex_init(&chip->rw_lock);
	INIT_DELAYED_WORK(&chip->update_jeita_setting,
			update_jeita_setting);
	init_completion(&chip->sram_access);

	rc = fg_of_init(chip);
	if (rc) {
		pr_err("failed to parse devicetree rc%d\n", rc);
		goto of_init_fail;
	}

	spmi_for_each_container_dev(spmi_resource, spmi) {
		if (!spmi_resource) {
			pr_err("qpnp_chg: spmi resource absent\n");
			rc = -ENXIO;
			return rc;
			goto of_init_fail;
		}

		resource = spmi_get_resource(spmi, spmi_resource,
@@ -388,7 +868,7 @@ static int fg_probe(struct spmi_device *spmi)
			pr_err("node %s IO resource absent!\n",
				spmi->dev.of_node->full_name);
			rc = -ENXIO;
			return rc;
			goto of_init_fail;
		}

		if (strcmp("qcom,fg-adc-vbat",
@@ -405,13 +885,16 @@ static int fg_probe(struct spmi_device *spmi)
				resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
		if (rc) {
			pr_err("Peripheral subtype read failed rc=%d\n", rc);
			return rc;
			goto of_init_fail;
		}

		switch (subtype) {
		case FG_SOC:
			chip->soc_base = resource->start;
			break;
		case FG_MEMIF:
			chip->mem_base = resource->start;
			break;
		default:
			pr_err("Invalid peripheral subtype=0x%x\n", subtype);
			rc = -EINVAL;
@@ -423,13 +906,15 @@ static int fg_probe(struct spmi_device *spmi)
	chip->bms_psy.properties = fg_power_props;
	chip->bms_psy.num_properties = ARRAY_SIZE(fg_power_props);
	chip->bms_psy.get_property = fg_power_get_property;
	chip->bms_psy.set_property = fg_power_set_property;
	chip->bms_psy.supplied_to = fg_supplicants;
	chip->bms_psy.num_supplicants = ARRAY_SIZE(fg_supplicants);
	chip->bms_psy.property_is_writeable = fg_property_is_writeable;

	rc = power_supply_register(chip->dev, &chip->bms_psy);
	if (rc < 0) {
		pr_err("batt failed to register rc = %d\n", rc);
		return rc;
		goto of_init_fail;
	}

	rc = fg_init_irqs(chip);
@@ -444,6 +929,8 @@ static int fg_probe(struct spmi_device *spmi)

power_supply_unregister:
	power_supply_unregister(&chip->bms_psy);
of_init_fail:
	mutex_destroy(&chip->rw_lock);
	return rc;
}