// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2016-2017, 2020-2021, The Linux Foundation. All rights reserved.
 * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
 */

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

#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/power_supply.h>
#include <dt-bindings/iio/qti_power_supply_iio.h>
#include <linux/iio/consumer.h>

#define FG_ADC_RR_EN_CTL			0x46
#define FG_ADC_RR_SKIN_TEMP_LSB			0x50
#define FG_ADC_RR_SKIN_TEMP_MSB			0x51
#define FG_ADC_RR_RR_ADC_CTL			0x52
#define FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL_MASK	0x8
#define FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL	BIT(3)
#define FG_ADC_RR_ADC_LOG			0x53
#define FG_ADC_RR_ADC_LOG_CLR_CTRL		BIT(0)

#define FG_ADC_RR_FAKE_BATT_LOW_LSB		0x58
#define FG_ADC_RR_FAKE_BATT_LOW_MSB		0x59
#define FG_ADC_RR_FAKE_BATT_HIGH_LSB		0x5A
#define FG_ADC_RR_FAKE_BATT_HIGH_MSB		0x5B

#define FG_ADC_RR_BATT_ID_CTRL			0x60
#define FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV	BIT(0)
#define FG_ADC_RR_BATT_ID_TRIGGER		0x61
#define FG_ADC_RR_BATT_ID_TRIGGER_CTL		BIT(0)
#define FG_ADC_RR_BATT_ID_STS			0x62
#define FG_ADC_RR_BATT_ID_CFG			0x63
#define FG_ADC_RR_BATT_ID_5_LSB			0x66
#define FG_ADC_RR_BATT_ID_5_MSB			0x67
#define FG_ADC_RR_BATT_ID_15_LSB		0x68
#define FG_ADC_RR_BATT_ID_15_MSB		0x69
#define FG_ADC_RR_BATT_ID_150_LSB		0x6A
#define FG_ADC_RR_BATT_ID_150_MSB		0x6B

#define FG_ADC_RR_BATT_THERM_CTRL		0x70
#define FG_ADC_RR_BATT_THERM_TRIGGER		0x71
#define FG_ADC_RR_BATT_THERM_STS		0x72
#define FG_ADC_RR_BATT_THERM_CFG		0x73
#define FG_ADC_RR_BATT_THERM_LSB		0x74
#define FG_ADC_RR_BATT_THERM_MSB		0x75
#define FG_ADC_RR_BATT_THERM_FREQ		0x76

#define FG_ADC_RR_AUX_THERM_CTRL		0x80
#define FG_ADC_RR_AUX_THERM_TRIGGER		0x81
#define FG_ADC_RR_AUX_THERM_STS			0x82
#define FG_ADC_RR_AUX_THERM_CFG			0x83
#define FG_ADC_RR_AUX_THERM_LSB			0x84
#define FG_ADC_RR_AUX_THERM_MSB			0x85

#define FG_ADC_RR_SKIN_HOT			0x86
#define FG_ADC_RR_SKIN_TOO_HOT			0x87

#define FG_ADC_RR_AUX_THERM_C1			0x88
#define FG_ADC_RR_AUX_THERM_C2			0x89
#define FG_ADC_RR_AUX_THERM_C3			0x8A
#define FG_ADC_RR_AUX_THERM_HALF_RANGE		0x8B

#define FG_ADC_RR_USB_IN_V_CTRL			0x90
#define FG_ADC_RR_USB_IN_V_TRIGGER		0x91
#define FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK	0x80
#define FG_ADC_RR_USB_IN_V_EVERY_CYCLE		BIT(7)
#define FG_ADC_RR_USB_IN_V_STS			0x92
#define FG_ADC_RR_USB_IN_V_LSB			0x94
#define FG_ADC_RR_USB_IN_V_MSB			0x95
#define FG_ADC_RR_USB_IN_I_CTRL			0x98
#define FG_ADC_RR_USB_IN_I_TRIGGER		0x99
#define FG_ADC_RR_USB_IN_I_STS			0x9A
#define FG_ADC_RR_USB_IN_I_LSB			0x9C
#define FG_ADC_RR_USB_IN_I_MSB			0x9D

#define FG_ADC_RR_DC_IN_V_CTRL			0xA0
#define FG_ADC_RR_DC_IN_V_TRIGGER		0xA1
#define FG_ADC_RR_DC_IN_V_STS			0xA2
#define FG_ADC_RR_DC_IN_V_LSB			0xA4
#define FG_ADC_RR_DC_IN_V_MSB			0xA5
#define FG_ADC_RR_DC_IN_I_CTRL			0xA8
#define FG_ADC_RR_DC_IN_I_TRIGGER		0xA9
#define FG_ADC_RR_DC_IN_I_STS			0xAA
#define FG_ADC_RR_DC_IN_I_LSB			0xAC
#define FG_ADC_RR_DC_IN_I_MSB			0xAD

#define FG_ADC_RR_PMI_DIE_TEMP_CTRL		0xB0
#define FG_ADC_RR_PMI_DIE_TEMP_TRIGGER		0xB1
#define FG_ADC_RR_PMI_DIE_TEMP_STS		0xB2
#define FG_ADC_RR_PMI_DIE_TEMP_CFG		0xB3
#define FG_ADC_RR_PMI_DIE_TEMP_LSB		0xB4
#define FG_ADC_RR_PMI_DIE_TEMP_MSB		0xB5

#define FG_ADC_RR_CHARGER_TEMP_CTRL		0xB8
#define FG_ADC_RR_CHARGER_TEMP_TRIGGER		0xB9
#define FG_ADC_RR_CHARGER_TEMP_STS		0xBA
#define FG_ADC_RR_CHARGER_TEMP_CFG		0xBB
#define FG_ADC_RR_CHARGER_TEMP_LSB		0xBC
#define FG_ADC_RR_CHARGER_TEMP_MSB		0xBD
#define FG_ADC_RR_CHARGER_HOT			0xBE
#define FG_ADC_RR_CHARGER_TOO_HOT		0xBF

#define FG_ADC_RR_GPIO_CTRL			0xC0
#define FG_ADC_RR_GPIO_TRIGGER			0xC1
#define FG_ADC_RR_GPIO_STS			0xC2
#define FG_ADC_RR_GPIO_LSB			0xC4
#define FG_ADC_RR_GPIO_MSB			0xC5

#define FG_ADC_RR_ATEST_CTRL			0xC8
#define FG_ADC_RR_ATEST_TRIGGER			0xC9
#define FG_ADC_RR_ATEST_STS			0xCA
#define FG_ADC_RR_ATEST_LSB			0xCC
#define FG_ADC_RR_ATEST_MSB			0xCD
#define FG_ADC_RR_SEC_ACCESS			0xD0

#define FG_ADC_RR_PERPH_RESET_CTL2		0xD9
#define FG_ADC_RR_PERPH_RESET_CTL3		0xDA
#define FG_ADC_RR_PERPH_RESET_CTL4		0xDB
#define FG_ADC_RR_INT_TEST1			0xE0
#define FG_ADC_RR_INT_TEST_VAL			0xE1

#define FG_ADC_RR_TM_TRIGGER_CTRLS		0xE2
#define FG_ADC_RR_TM_ADC_CTRLS			0xE3
#define FG_ADC_RR_TM_CNL_CTRL			0xE4
#define FG_ADC_RR_TM_BATT_ID_CTRL		0xE5
#define FG_ADC_RR_TM_THERM_CTRL			0xE6
#define FG_ADC_RR_TM_CONV_STS			0xE7
#define FG_ADC_RR_TM_ADC_READ_LSB		0xE8
#define FG_ADC_RR_TM_ADC_READ_MSB		0xE9
#define FG_ADC_RR_TM_ATEST_MUX_1		0xEA
#define FG_ADC_RR_TM_ATEST_MUX_2		0xEB
#define FG_ADC_RR_TM_REFERENCES			0xED
#define FG_ADC_RR_TM_MISC_CTL			0xEE
#define FG_ADC_RR_TM_RR_CTRL			0xEF

#define FG_ADC_RR_BATT_ID_5_MA			5
#define FG_ADC_RR_BATT_ID_15_MA			15
#define FG_ADC_RR_BATT_ID_150_MA		150
#define FG_ADC_RR_BATT_ID_RANGE			820

#define FG_ADC_BITS				10
#define FG_MAX_ADC_READINGS			(1 << FG_ADC_BITS)
#define FG_ADC_RR_FS_VOLTAGE_MV			2500

/* BATT_THERM 0.25K/LSB */
#define FG_ADC_RR_BATT_THERM_LSB_K		4

#define FG_ADC_RR_TEMP_FS_VOLTAGE_NUM		5000000
#define FG_ADC_RR_TEMP_FS_VOLTAGE_DEN		3
#define FG_ADC_RR_DIE_TEMP_OFFSET		601400
#define FG_ADC_RR_DIE_TEMP_SLOPE		2
#define FG_ADC_RR_DIE_TEMP_OFFSET_MILLI_DEGC	25000

#define FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV		1303168
#define FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C	3784
#define FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV	1338433
#define FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C	3655
#define FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV	1309001
#define FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C	3403
#define FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV	1295898
#define FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C	3596
#define FG_ADC_RR_CHG_TEMP_660_MGNA_OFFSET_UV	1314779
#define FG_RR_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C	3496
#define FG_ADC_RR_CHG_TEMP_OFFSET_MILLI_DEGC	25000
#define FG_ADC_RR_CHG_THRESHOLD_SCALE		4

#define FG_ADC_RR_VOLT_INPUT_FACTOR		8
#define FG_ADC_RR_CURR_INPUT_FACTOR		2000
#define FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL	1886
#define FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL	9
#define FG_ADC_RR_CURR_USBIN_660_UV_VAL	579500

#define FG_ADC_SCALE_MILLI_FACTOR		1000
#define FG_ADC_KELVINMIL_CELSIUSMIL		273150

#define FG_ADC_RR_GPIO_FS_RANGE			5000
#define FG_RR_ADC_COHERENT_CHECK_RETRY		5
#define FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN	16
#define FG_RR_ADC_STS_CHANNEL_READING_MASK	0x3
#define FG_RR_ADC_STS_CHANNEL_STS		0x2

#define FG_RR_CONV_CONTINUOUS_TIME_MIN_MS	50
#define FG_RR_CONV_CONT_CBK_TIME_MIN_MS	10
#define FG_RR_CONV_MAX_RETRY_CNT		50
#define FG_RR_TP_REV_VERSION1		21
#define FG_RR_TP_REV_VERSION2		29
#define FG_RR_TP_REV_VERSION3		32

/*
 * The channel number is not a physical index in hardware,
 * rather it's a list of supported channels and an index to
 * select the respective channel properties such as scaling
 * the result. Add any new additional channels supported by
 * the RR ADC before RR_ADC_MAX.
 */
enum rradc_channel_id {
	RR_ADC_BATT_ID = 0,
	RR_ADC_BATT_THERM,
	RR_ADC_SKIN_TEMP,
	RR_ADC_USBIN_I,
	RR_ADC_USBIN_V,
	RR_ADC_DCIN_I,
	RR_ADC_DCIN_V,
	RR_ADC_DIE_TEMP,
	RR_ADC_CHG_TEMP,
	RR_ADC_GPIO,
	RR_ADC_CHG_HOT_TEMP,
	RR_ADC_CHG_TOO_HOT_TEMP,
	RR_ADC_SKIN_HOT_TEMP,
	RR_ADC_SKIN_TOO_HOT_TEMP,
	RR_ADC_MAX
};

struct rradc_chip {
	struct device			*dev;
	struct mutex			lock;
	struct regmap			*regmap;
	u16				base;
	struct iio_chan_spec		*iio_chans;
	unsigned int			nchannels;
	struct rradc_chan_prop		*chan_props;
	struct device_node		*revid_dev_node;
	struct pmic_revid_data		*pmic_fab_id;
	int volt;
	struct power_supply		*usb_trig;
	struct power_supply		*batt_psy;
	struct notifier_block		nb;
	bool				conv_cbk;
	bool				rradc_fg_reset_wa;
	struct work_struct	psy_notify_work;
	struct iio_channel	**ext_iio_chans;
};

struct rradc_channels {
	const char			*datasheet_name;
	enum iio_chan_type		type;
	long				info_mask;
	u8				lsb;
	u8				msb;
	u8				sts;
	int (*scale)(struct rradc_chip *chip, struct rradc_chan_prop *prop,
					u16 adc_code, int *result);
};

struct rradc_chan_prop {
	enum rradc_channel_id		channel;
	uint32_t			channel_data;
	int (*scale)(struct rradc_chip *chip, struct rradc_chan_prop *prop,
					u16 adc_code, int *result);
};

/* External IIO Channels for rradc.c */
enum rradc_ext_iio_channels {
	RRADC_FG_GEN3_FG_RESET_CLOCK,
};

/* External IIO channels */
static const char * const rradc_ext_iio_chan_name[] = {
	[RRADC_FG_GEN3_FG_RESET_CLOCK] = "fg_reset_clock",
};

static int rradc_masked_write(struct rradc_chip *rr_adc, u16 offset, u8 mask,
						u8 val)
{
	int rc;

	rc = regmap_update_bits(rr_adc->regmap, rr_adc->base + offset,
								mask, val);
	if (rc) {
		pr_err("spmi write failed: addr=%03X, rc=%d\n", offset, rc);
		return rc;
	}

	return rc;
}

static int rradc_read(struct rradc_chip *rr_adc, u16 offset, u8 *data, int len)
{
	int rc = 0, retry_cnt = 0, i = 0;
	u8 data_check[FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN];
	bool coherent_err = false;

	if (len > FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN) {
		pr_err("Increase the buffer length\n");
		return -EINVAL;
	}

	while (retry_cnt < FG_RR_ADC_COHERENT_CHECK_RETRY) {
		rc = regmap_bulk_read(rr_adc->regmap, rr_adc->base + offset,
							data, len);
		if (rc < 0) {
			pr_err("rr_adc reg 0x%x failed :%d\n", offset, rc);
			return rc;
		}

		rc = regmap_bulk_read(rr_adc->regmap, rr_adc->base + offset,
							data_check, len);
		if (rc < 0) {
			pr_err("rr_adc reg 0x%x failed :%d\n", offset, rc);
			return rc;
		}

		for (i = 0; i < len; i++) {
			if (data[i] != data_check[i])
				coherent_err = true;
		}

		if (coherent_err) {
			retry_cnt++;
			coherent_err = false;
			pr_debug("retry_cnt:%d\n", retry_cnt);
		} else {
			break;
		}
	}

	if (retry_cnt == FG_RR_ADC_COHERENT_CHECK_RETRY)
		pr_err("Retry exceeded for coherrency check\n");

	return rc;
}

static int rradc_post_process_batt_id(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_ohms)
{
	uint32_t current_value;
	int64_t r_id;

	current_value = prop->channel_data;
	r_id = ((int64_t)adc_code * FG_ADC_RR_FS_VOLTAGE_MV);
	r_id = div64_s64(r_id, (FG_MAX_ADC_READINGS * current_value));
	*result_ohms = (r_id * FG_ADC_SCALE_MILLI_FACTOR);

	return 0;
}

static int rradc_post_process_therm(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_millidegc)
{
	int64_t temp;

	/* K = code/4 */
	temp = ((int64_t)adc_code * FG_ADC_SCALE_MILLI_FACTOR);
	temp = div64_s64(temp, FG_ADC_RR_BATT_THERM_LSB_K);
	*result_millidegc = temp - FG_ADC_KELVINMIL_CELSIUSMIL;

	return 0;
}

static int rradc_post_process_volt(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_uv)
{
	int64_t uv = 0;

	/* 8x input attenuation; 2.5V ADC full scale */
	uv = ((int64_t)adc_code * FG_ADC_RR_VOLT_INPUT_FACTOR);
	uv *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
	uv = div64_s64(uv, FG_MAX_ADC_READINGS);
	*result_uv = uv;

	return 0;
}

static int rradc_post_process_usbin_curr(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_ua)
{
	int64_t ua = 0, scale = 0;

	if (!prop)
		return -EINVAL;
	if (chip->revid_dev_node) {
		switch (chip->pmic_fab_id->pmic_subtype) {
		case PM660_SUBTYPE:
			if (((chip->pmic_fab_id->tp_rev
				>= FG_RR_TP_REV_VERSION1)
			&& (chip->pmic_fab_id->tp_rev
				<= FG_RR_TP_REV_VERSION2))
			|| (chip->pmic_fab_id->tp_rev
				>= FG_RR_TP_REV_VERSION3)) {
				chip->volt = div64_s64(chip->volt, 1000);
				chip->volt = chip->volt *
					FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL;
				chip->volt = FG_ADC_RR_CURR_USBIN_660_UV_VAL -
					(chip->volt);
				chip->volt = div64_s64(1000000000, chip->volt);
				scale = chip->volt;
			} else
				scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
			break;
		case PMI8998_SUBTYPE:
			scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
			break;
		default:
			pr_err("No PMIC subtype found\n");
			return -EINVAL;
		}
	}

	/* scale * V/A; 2.5V ADC full scale */
	ua = ((int64_t)adc_code * scale);
	ua *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
	ua = div64_s64(ua, (FG_MAX_ADC_READINGS * 1000));
	*result_ua = ua;

	return 0;
}

static int rradc_post_process_dcin_curr(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_ua)
{
	int64_t ua = 0;

	if (!prop)
		return -EINVAL;

	/* 0.5 V/A; 2.5V ADC full scale */
	ua = ((int64_t)adc_code * FG_ADC_RR_CURR_INPUT_FACTOR);
	ua *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
	ua = div64_s64(ua, (FG_MAX_ADC_READINGS * 1000));
	*result_ua = ua;

	return 0;
}

static int rradc_post_process_die_temp(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_millidegc)
{
	int64_t temp = 0;

	temp = ((int64_t)adc_code * FG_ADC_RR_TEMP_FS_VOLTAGE_NUM);
	temp = div64_s64(temp, (FG_ADC_RR_TEMP_FS_VOLTAGE_DEN *
					FG_MAX_ADC_READINGS));
	temp -= FG_ADC_RR_DIE_TEMP_OFFSET;
	temp = div64_s64(temp, FG_ADC_RR_DIE_TEMP_SLOPE);
	temp += FG_ADC_RR_DIE_TEMP_OFFSET_MILLI_DEGC;
	*result_millidegc = temp;

	return 0;
}

static int rradc_get_660_fab_coeff(struct rradc_chip *chip,
		int64_t *offset, int64_t *slope)
{
	switch (chip->pmic_fab_id->fab_id) {
	case PM660_FAB_ID_GF:
		*offset = FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV;
		*slope = FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C;
		break;
	case PM660_FAB_ID_TSMC:
		*offset = FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV;
		*slope = FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C;
		break;
	default:
		*offset = FG_ADC_RR_CHG_TEMP_660_MGNA_OFFSET_UV;
		*slope = FG_RR_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C;
	}

	return 0;
}

static int rradc_get_8998_fab_coeff(struct rradc_chip *chip,
		int64_t *offset, int64_t *slope)
{
	switch (chip->pmic_fab_id->fab_id) {
	case PMI8998_FAB_ID_GF:
		*offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
		*slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
		break;
	case PMI8998_FAB_ID_SMIC:
		*offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
		*slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int rradc_post_process_chg_temp_hot(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_millidegc)
{
	int64_t uv = 0, offset = 0, slope = 0;
	int rc = 0;

	if (chip->revid_dev_node) {
		switch (chip->pmic_fab_id->pmic_subtype) {
		case PM660_SUBTYPE:
			rc = rradc_get_660_fab_coeff(chip, &offset, &slope);
			if (rc < 0) {
				pr_err("Unable to get fab id coefficients\n");
				return -EINVAL;
			}
			break;
		case PMI8998_SUBTYPE:
			rc = rradc_get_8998_fab_coeff(chip, &offset, &slope);
			if (rc < 0) {
				pr_err("Unable to get fab id coefficients\n");
				return -EINVAL;
			}
			break;
		default:
			pr_err("No PMIC subtype found\n");
			return -EINVAL;
		}
	} else {
		pr_err("No temperature scaling coefficients\n");
		return -EINVAL;
	}

	uv = (int64_t) adc_code * FG_ADC_RR_CHG_THRESHOLD_SCALE;
	uv = uv * FG_ADC_RR_TEMP_FS_VOLTAGE_NUM;
	uv = div64_s64(uv, (FG_ADC_RR_TEMP_FS_VOLTAGE_DEN *
					FG_MAX_ADC_READINGS));
	uv = offset - uv;
	uv = div64_s64((uv * FG_ADC_SCALE_MILLI_FACTOR), slope);
	uv = uv + FG_ADC_RR_CHG_TEMP_OFFSET_MILLI_DEGC;
	*result_millidegc = uv;

	return 0;
}

static int rradc_post_process_skin_temp_hot(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_millidegc)
{
	int64_t temp = 0;

	temp = (int64_t) adc_code;
	temp = div64_s64(temp, 2);
	temp = temp - 30;
	temp *= FG_ADC_SCALE_MILLI_FACTOR;
	*result_millidegc = temp;

	return 0;
}

static int rradc_post_process_chg_temp(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_millidegc)
{
	int64_t uv = 0, offset = 0, slope = 0;
	int rc = 0;

	if (chip->revid_dev_node) {
		switch (chip->pmic_fab_id->pmic_subtype) {
		case PM660_SUBTYPE:
			rc = rradc_get_660_fab_coeff(chip, &offset, &slope);
			if (rc < 0) {
				pr_err("Unable to get fab id coefficients\n");
				return -EINVAL;
			}
			break;
		case PMI8998_SUBTYPE:
			rc = rradc_get_8998_fab_coeff(chip, &offset, &slope);
			if (rc < 0) {
				pr_err("Unable to get fab id coefficients\n");
				return -EINVAL;
			}
			break;
		default:
			pr_err("No PMIC subtype found\n");
			return -EINVAL;
		}
	} else {
		pr_err("No temperature scaling coefficients\n");
		return -EINVAL;
	}

	uv = ((int64_t) adc_code * FG_ADC_RR_TEMP_FS_VOLTAGE_NUM);
	uv = div64_s64(uv, (FG_ADC_RR_TEMP_FS_VOLTAGE_DEN *
					FG_MAX_ADC_READINGS));
	uv = offset - uv;
	uv = div64_s64((uv * FG_ADC_SCALE_MILLI_FACTOR), slope);
	uv += FG_ADC_RR_CHG_TEMP_OFFSET_MILLI_DEGC;
	*result_millidegc = uv;

	return 0;
}

static int rradc_post_process_gpio(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 adc_code,
			int *result_mv)
{
	int64_t mv = 0;

	/* 5V ADC full scale, 10 bit */
	mv = ((int64_t)adc_code * FG_ADC_RR_GPIO_FS_RANGE);
	mv = div64_s64(mv, FG_MAX_ADC_READINGS);
	*result_mv = mv;

	return 0;
}

#define RR_ADC_CHAN(_dname, _type, _mask, _scale, _lsb, _msb, _sts)	\
	{								\
		.datasheet_name = (_dname),				\
		.type = _type,						\
		.info_mask = _mask,					\
		.scale = _scale,					\
		.lsb = _lsb,						\
		.msb = _msb,						\
		.sts = _sts,						\
	},								\

#define RR_ADC_CHAN_TEMP(_dname, _scale, mask, _lsb, _msb, _sts)	\
	RR_ADC_CHAN(_dname, IIO_TEMP,					\
		mask,							\
		_scale, _lsb, _msb, _sts)				\

#define RR_ADC_CHAN_VOLT(_dname, _scale, _lsb, _msb, _sts)		\
	RR_ADC_CHAN(_dname, IIO_VOLTAGE,				\
		  BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
		  _scale, _lsb, _msb, _sts)				\

#define RR_ADC_CHAN_CURRENT(_dname, _scale, _lsb, _msb, _sts)		\
	RR_ADC_CHAN(_dname, IIO_CURRENT,				\
		  BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
		  _scale, _lsb, _msb, _sts)				\

#define RR_ADC_CHAN_RESISTANCE(_dname, _scale, _lsb, _msb, _sts)	\
	RR_ADC_CHAN(_dname, IIO_RESISTANCE,				\
		  BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
		  _scale, _lsb, _msb, _sts)				\

static const struct rradc_channels rradc_chans[] = {
	RR_ADC_CHAN_RESISTANCE("batt_id", rradc_post_process_batt_id,
			FG_ADC_RR_BATT_ID_5_LSB, FG_ADC_RR_BATT_ID_5_MSB,
			FG_ADC_RR_BATT_ID_STS)
	RR_ADC_CHAN_TEMP("batt_therm", &rradc_post_process_therm,
			BIT(IIO_CHAN_INFO_RAW),
			FG_ADC_RR_BATT_THERM_LSB, FG_ADC_RR_BATT_THERM_MSB,
			FG_ADC_RR_BATT_THERM_STS)
	RR_ADC_CHAN_TEMP("skin_temp", &rradc_post_process_therm,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_SKIN_TEMP_LSB, FG_ADC_RR_SKIN_TEMP_MSB,
			FG_ADC_RR_AUX_THERM_STS)
	RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_usbin_curr,
			FG_ADC_RR_USB_IN_I_LSB, FG_ADC_RR_USB_IN_I_MSB,
			FG_ADC_RR_USB_IN_I_STS)
	RR_ADC_CHAN_VOLT("usbin_v", &rradc_post_process_volt,
			FG_ADC_RR_USB_IN_V_LSB, FG_ADC_RR_USB_IN_V_MSB,
			FG_ADC_RR_USB_IN_V_STS)
	RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_dcin_curr,
			FG_ADC_RR_DC_IN_I_LSB, FG_ADC_RR_DC_IN_I_MSB,
			FG_ADC_RR_DC_IN_I_STS)
	RR_ADC_CHAN_VOLT("dcin_v", &rradc_post_process_volt,
			FG_ADC_RR_DC_IN_V_LSB, FG_ADC_RR_DC_IN_V_MSB,
			FG_ADC_RR_DC_IN_V_STS)
	RR_ADC_CHAN_TEMP("die_temp", &rradc_post_process_die_temp,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_PMI_DIE_TEMP_LSB, FG_ADC_RR_PMI_DIE_TEMP_MSB,
			FG_ADC_RR_PMI_DIE_TEMP_STS)
	RR_ADC_CHAN_TEMP("chg_temp", &rradc_post_process_chg_temp,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_CHARGER_TEMP_LSB, FG_ADC_RR_CHARGER_TEMP_MSB,
			FG_ADC_RR_CHARGER_TEMP_STS)
	RR_ADC_CHAN_VOLT("gpio", &rradc_post_process_gpio,
			FG_ADC_RR_GPIO_LSB, FG_ADC_RR_GPIO_MSB,
			FG_ADC_RR_GPIO_STS)
	RR_ADC_CHAN_TEMP("chg_temp_hot", &rradc_post_process_chg_temp_hot,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_CHARGER_HOT, FG_ADC_RR_CHARGER_HOT,
			FG_ADC_RR_CHARGER_TEMP_STS)
	RR_ADC_CHAN_TEMP("chg_temp_too_hot", &rradc_post_process_chg_temp_hot,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_CHARGER_TOO_HOT, FG_ADC_RR_CHARGER_TOO_HOT,
			FG_ADC_RR_CHARGER_TEMP_STS)
	RR_ADC_CHAN_TEMP("skin_temp_hot", &rradc_post_process_skin_temp_hot,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_SKIN_HOT, FG_ADC_RR_SKIN_HOT,
			FG_ADC_RR_AUX_THERM_STS)
	RR_ADC_CHAN_TEMP("skin_temp_too_hot", &rradc_post_process_skin_temp_hot,
			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
			FG_ADC_RR_SKIN_TOO_HOT, FG_ADC_RR_SKIN_TOO_HOT,
			FG_ADC_RR_AUX_THERM_STS)
};

static bool rradc_is_batt_psy_available(struct rradc_chip *chip)
{
	if (!chip->batt_psy)
		chip->batt_psy = power_supply_get_by_name("battery");

	if (!chip->batt_psy)
		return false;

	return true;
}

bool is_chan_valid(struct rradc_chip *chip,
		enum rradc_ext_iio_channels chan)
{
	int rc;

	if (IS_ERR(chip->ext_iio_chans[chan]))
		return false;

	if (!chip->ext_iio_chans[chan]) {
		chip->ext_iio_chans[chan] = iio_channel_get(chip->dev,
					rradc_ext_iio_chan_name[chan]);
		if (IS_ERR(chip->ext_iio_chans[chan])) {
			rc = PTR_ERR(chip->ext_iio_chans[chan]);
			if (rc == -EPROBE_DEFER)
				chip->ext_iio_chans[chan] = NULL;

			pr_err("Failed to get IIO channel %s, rc=%d\n",
				rradc_ext_iio_chan_name[chan], rc);
			return false;
		}
	}

	return true;
}

int rradc_write_iio_chan(struct rradc_chip *chip,
	enum rradc_ext_iio_channels chan, int val)
{
	if (is_chan_valid(chip, chan))
		return iio_write_channel_raw(chip->ext_iio_chans[chan],
						val);

	return -EINVAL;
}

static bool rradc_is_bms_psy_available(struct rradc_chip *chip)
{
	if (is_chan_valid(chip, RRADC_FG_GEN3_FG_RESET_CLOCK))
		return true;

	return false;

}

static int rradc_enable_continuous_mode(struct rradc_chip *chip)
{
	int rc = 0;

	/* Clear channel log */
	rc = rradc_masked_write(chip, FG_ADC_RR_ADC_LOG,
			FG_ADC_RR_ADC_LOG_CLR_CTRL,
			FG_ADC_RR_ADC_LOG_CLR_CTRL);
	if (rc < 0) {
		pr_err("log ctrl update to clear failed:%d\n", rc);
		return rc;
	}

	rc = rradc_masked_write(chip, FG_ADC_RR_ADC_LOG,
		FG_ADC_RR_ADC_LOG_CLR_CTRL, 0);
	if (rc < 0) {
		pr_err("log ctrl update to not clear failed:%d\n", rc);
		return rc;
	}

	/* Switch to continuous mode */
	rc = rradc_masked_write(chip, FG_ADC_RR_RR_ADC_CTL,
		FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL_MASK,
		FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL);
	if (rc < 0) {
		pr_err("Update to continuous mode failed:%d\n", rc);
		return rc;
	}

	return rc;
}

static int rradc_disable_continuous_mode(struct rradc_chip *chip)
{
	int rc = 0;

	/* Switch to non continuous mode */
	rc = rradc_masked_write(chip, FG_ADC_RR_RR_ADC_CTL,
			FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL_MASK, 0);
	if (rc < 0) {
		pr_err("Update to non-continuous mode failed:%d\n", rc);
		return rc;
	}

	return rc;
}

static bool rradc_is_usb_present(struct rradc_chip *chip)
{
	union power_supply_propval pval;
	int rc;
	bool usb_present = false;

	if (!chip->usb_trig) {
		pr_debug("USB property not present\n");
		return usb_present;
	}

	rc = power_supply_get_property(chip->usb_trig,
			POWER_SUPPLY_PROP_PRESENT, &pval);
	usb_present = (rc < 0) ? 0 : pval.intval;

	return usb_present;
}

static int rradc_check_status_ready_with_retry(struct rradc_chip *chip,
		struct rradc_chan_prop *prop, u8 *buf, u16 status)
{
	int rc = 0, retry_cnt = 0, mask = 0;
	union power_supply_propval pval = {0, };

	switch (prop->channel) {
	case RR_ADC_BATT_ID:
		/* BATT_ID STS bit does not get set initially */
		mask = FG_RR_ADC_STS_CHANNEL_STS;
		break;
	default:
		mask = FG_RR_ADC_STS_CHANNEL_READING_MASK;
		break;
	}

	while (((buf[0] & mask) != mask) &&
			(retry_cnt < FG_RR_CONV_MAX_RETRY_CNT)) {
		pr_debug("%s is not ready; nothing to read:0x%x\n",
			rradc_chans[prop->channel].datasheet_name, buf[0]);

		if (((prop->channel == RR_ADC_CHG_TEMP) ||
			(prop->channel == RR_ADC_SKIN_TEMP) ||
			(prop->channel == RR_ADC_USBIN_I)) &&
					((!rradc_is_usb_present(chip)))) {
			pr_debug("USB not present for %d\n", prop->channel);
			rc = -ENODATA;
			break;
		}

		if ((chip->conv_cbk) && (prop->channel == RR_ADC_USBIN_V))
			msleep(FG_RR_CONV_CONT_CBK_TIME_MIN_MS);
		else
			msleep(FG_RR_CONV_CONTINUOUS_TIME_MIN_MS);

		retry_cnt++;
		rc = rradc_read(chip, status, buf, 1);
		if (rc < 0) {
			pr_err("status read failed:%d\n", rc);
			return rc;
		}
	}

	if ((retry_cnt >= FG_RR_CONV_MAX_RETRY_CNT) &&
		((prop->channel != RR_ADC_DCIN_V) &&
		(prop->channel != RR_ADC_DCIN_I)) &&
		chip->rradc_fg_reset_wa) {
		pr_err("rradc is hung, Proceed to recovery\n");
		if (rradc_is_bms_psy_available(chip)) {
			rc = rradc_write_iio_chan(chip,
				RRADC_FG_GEN3_FG_RESET_CLOCK, pval.intval);
			if (rc < 0) {
				pr_err("Couldn't reset FG clock rc=%d\n", rc);
				return rc;
			}
		} else {
			pr_err("Error obtaining bms power supply\n");
			rc = -EINVAL;
		}
	} else {
		if (retry_cnt >= FG_RR_CONV_MAX_RETRY_CNT)
			rc = -ENODATA;
	}

	return rc;
}

static int rradc_read_channel_with_continuous_mode(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u8 *buf)
{
	int rc = 0, ret = 0;
	u16 status = 0;

	rc = rradc_enable_continuous_mode(chip);
	if (rc < 0) {
		pr_err("Failed to switch to continuous mode\n");
		return rc;
	}

	status = rradc_chans[prop->channel].sts;
	rc = rradc_read(chip, status, buf, 1);
	if (rc < 0) {
		pr_err("status read failed:%d\n", rc);
		ret = rc;
		goto disable;
	}

	rc = rradc_check_status_ready_with_retry(chip, prop,
						buf, status);
	if (rc < 0) {
		pr_err("Status read failed:%d\n", rc);
		ret = rc;
	}

disable:
	rc = rradc_disable_continuous_mode(chip);
	if (rc < 0) {
		pr_err("Failed to switch to non continuous mode\n");
		ret = rc;
	}

	return ret;
}

static int rradc_enable_batt_id_channel(struct rradc_chip *chip, bool enable)
{
	int rc = 0;

	if (enable) {
		rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CTRL,
				FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV,
				FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV);
		if (rc < 0) {
			pr_err("Enabling BATT ID channel failed:%d\n", rc);
			return rc;
		}
	} else {
		rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CTRL,
				FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV, 0);
		if (rc < 0) {
			pr_err("Disabling BATT ID channel failed:%d\n", rc);
			return rc;
		}
	}

	return rc;
}

static int rradc_do_batt_id_conversion(struct rradc_chip *chip,
		struct rradc_chan_prop *prop, u16 *data, u8 *buf)
{
	int rc = 0, ret = 0;

	rc = rradc_enable_batt_id_channel(chip, true);
	if (rc < 0) {
		pr_err("Enabling BATT ID channel failed:%d\n", rc);
		return rc;
	}

	rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER,
				FG_ADC_RR_BATT_ID_TRIGGER_CTL,
				FG_ADC_RR_BATT_ID_TRIGGER_CTL);
	if (rc < 0) {
		pr_err("BATT_ID trigger set failed:%d\n", rc);
		ret = rc;
		rc = rradc_enable_batt_id_channel(chip, false);
		if (rc < 0)
			pr_err("Disabling BATT ID channel failed:%d\n", rc);
		return ret;
	}

	rc = rradc_read_channel_with_continuous_mode(chip, prop, buf);
	if (rc < 0) {
		pr_err("Error reading in continuous mode:%d\n", rc);
		ret = rc;
	}

	rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER,
			FG_ADC_RR_BATT_ID_TRIGGER_CTL, 0);
	if (rc < 0) {
		pr_err("BATT_ID trigger re-set failed:%d\n", rc);
		ret = rc;
	}

	rc = rradc_enable_batt_id_channel(chip, false);
	if (rc < 0) {
		pr_err("Disabling BATT ID channel failed:%d\n", rc);
		ret = rc;
	}

	return ret;
}

static int rradc_do_conversion(struct rradc_chip *chip,
			struct rradc_chan_prop *prop, u16 *data)
{
	int rc = 0, bytes_to_read = 0;
	u8 buf[6];
	u16 offset = 0, batt_id_5 = 0, batt_id_15 = 0, batt_id_150 = 0;
	u16 status = 0;

	mutex_lock(&chip->lock);

	switch (prop->channel) {
	case RR_ADC_BATT_ID:
		rc = rradc_do_batt_id_conversion(chip, prop, data, buf);
		if (rc < 0) {
			pr_err("Battery ID conversion failed:%d\n", rc);
			goto fail;
		}
		break;
	case RR_ADC_USBIN_V:
		/* Force conversion every cycle */
		rc = rradc_masked_write(chip, FG_ADC_RR_USB_IN_V_TRIGGER,
				FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK,
				FG_ADC_RR_USB_IN_V_EVERY_CYCLE);
		if (rc < 0) {
			pr_err("Force every cycle update failed:%d\n", rc);
			goto fail;
		}

		rc = rradc_read_channel_with_continuous_mode(chip, prop, buf);
		if (rc < 0) {
			pr_err("Error reading in continuous mode:%d\n", rc);
			goto fail;
		}

		/* Restore usb_in trigger */
		rc = rradc_masked_write(chip, FG_ADC_RR_USB_IN_V_TRIGGER,
				FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK, 0);
		if (rc < 0) {
			pr_err("Restore every cycle update failed:%d\n", rc);
			goto fail;
		}
		break;
	case RR_ADC_DIE_TEMP:
		/* Force conversion every cycle */
		rc = rradc_masked_write(chip, FG_ADC_RR_PMI_DIE_TEMP_TRIGGER,
				FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK,
				FG_ADC_RR_USB_IN_V_EVERY_CYCLE);
		if (rc < 0) {
			pr_err("Force every cycle update failed:%d\n", rc);
			goto fail;
		}

		rc = rradc_read_channel_with_continuous_mode(chip, prop, buf);
		if (rc < 0) {
			pr_err("Error reading in continuous mode:%d\n", rc);
			goto fail;
		}

		/* Restore aux_therm trigger */
		rc = rradc_masked_write(chip, FG_ADC_RR_PMI_DIE_TEMP_TRIGGER,
				FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK, 0);
		if (rc < 0) {
			pr_err("Restore every cycle update failed:%d\n", rc);
			goto fail;
		}
		break;
	case RR_ADC_CHG_HOT_TEMP:
	case RR_ADC_CHG_TOO_HOT_TEMP:
	case RR_ADC_SKIN_HOT_TEMP:
	case RR_ADC_SKIN_TOO_HOT_TEMP:
		pr_debug("Read only the data registers\n");
		break;
	default:
		status = rradc_chans[prop->channel].sts;
		rc = rradc_read(chip, status, buf, 1);
		if (rc < 0) {
			pr_err("status read failed:%d\n", rc);
			goto fail;
		}

		rc = rradc_check_status_ready_with_retry(chip, prop,
						buf, status);
		if (rc < 0) {
			pr_debug("Status read failed:%d\n", rc);
			rc = -ENODATA;
			goto fail;
		}
		break;
	}

	offset = rradc_chans[prop->channel].lsb;
	if (prop->channel == RR_ADC_BATT_ID)
		bytes_to_read = 6;
	else if ((prop->channel == RR_ADC_CHG_HOT_TEMP) ||
		(prop->channel == RR_ADC_CHG_TOO_HOT_TEMP) ||
		(prop->channel == RR_ADC_SKIN_HOT_TEMP) ||
		(prop->channel == RR_ADC_SKIN_TOO_HOT_TEMP))
		bytes_to_read = 1;
	else
		bytes_to_read = 2;

	buf[0] = 0;
	rc = rradc_read(chip, offset, buf, bytes_to_read);
	if (rc) {
		pr_err("read data failed\n");
		goto fail;
	}

	if (prop->channel == RR_ADC_BATT_ID) {
		batt_id_150 = (buf[5] << 8) | buf[4];
		batt_id_15 = (buf[3] << 8) | buf[2];
		batt_id_5 = (buf[1] << 8) | buf[0];
		if ((!batt_id_150) && (!batt_id_15) && (!batt_id_5)) {
			pr_err("Invalid batt_id values with all zeros\n");
			rc = -EINVAL;
			goto fail;
		}

		if (batt_id_150 <= FG_ADC_RR_BATT_ID_RANGE) {
			pr_debug("Batt_id_150 is chosen\n");
			*data = batt_id_150;
			prop->channel_data = FG_ADC_RR_BATT_ID_150_MA;
		} else if (batt_id_15 <= FG_ADC_RR_BATT_ID_RANGE) {
			pr_debug("Batt_id_15 is chosen\n");
			*data = batt_id_15;
			prop->channel_data = FG_ADC_RR_BATT_ID_15_MA;
		} else {
			pr_debug("Batt_id_5 is chosen\n");
			*data = batt_id_5;
			prop->channel_data = FG_ADC_RR_BATT_ID_5_MA;
		}
	} else if ((prop->channel == RR_ADC_CHG_HOT_TEMP) ||
		(prop->channel == RR_ADC_CHG_TOO_HOT_TEMP) ||
		(prop->channel == RR_ADC_SKIN_HOT_TEMP) ||
		(prop->channel == RR_ADC_SKIN_TOO_HOT_TEMP)) {
		*data = buf[0];
	} else {
		*data = (buf[1] << 8) | buf[0];
	}
fail:
	mutex_unlock(&chip->lock);

	return rc;
}

static int rradc_read_raw(struct iio_dev *indio_dev,
			 struct iio_chan_spec const *chan, int *val, int *val2,
			 long mask)
{
	struct rradc_chip *chip = iio_priv(indio_dev);
	struct rradc_chan_prop *prop;
	u16 adc_code;
	int rc = 0;

	if (chan->address >= RR_ADC_MAX) {
		pr_err("Invalid channel index:%ld\n", chan->address);
		return -EINVAL;
	}

	switch (mask) {
	case IIO_CHAN_INFO_PROCESSED:
		if (((chip->pmic_fab_id->tp_rev
				>= FG_RR_TP_REV_VERSION1)
		&& (chip->pmic_fab_id->tp_rev
				<= FG_RR_TP_REV_VERSION2))
		|| (chip->pmic_fab_id->tp_rev
				>= FG_RR_TP_REV_VERSION3)) {
			if (chan->address == RR_ADC_USBIN_I) {
				prop = &chip->chan_props[RR_ADC_USBIN_V];
				rc = rradc_do_conversion(chip, prop, &adc_code);
				if (rc)
					break;
				prop->scale(chip, prop, adc_code, &chip->volt);
			}
		}

		prop = &chip->chan_props[chan->address];
		rc = rradc_do_conversion(chip, prop, &adc_code);
		if (rc)
			break;

		prop->scale(chip, prop, adc_code, val);

		return IIO_VAL_INT;
	case IIO_CHAN_INFO_RAW:
		prop = &chip->chan_props[chan->address];
		rc = rradc_do_conversion(chip, prop, &adc_code);
		if (rc)
			break;

		*val = (int) adc_code;

		return IIO_VAL_INT;
	default:
		rc = -EINVAL;
		break;
	}

	return rc;
}

static void psy_notify_work(struct work_struct *work)
{
	struct rradc_chip *chip = container_of(work,
			struct rradc_chip, psy_notify_work);

	struct rradc_chan_prop *prop;
	union power_supply_propval pval = {0, };
	u16 adc_code;
	int rc = 0;

	if (rradc_is_batt_psy_available(chip)) {
		rc = power_supply_get_property(chip->batt_psy,
			POWER_SUPPLY_PROP_STATUS, &pval);
		if (rc < 0)
			pr_err("Error obtaining battery status, rc=%d\n", rc);

		if (pval.intval == POWER_SUPPLY_STATUS_CHARGING) {
			chip->conv_cbk = true;
			prop = &chip->chan_props[RR_ADC_USBIN_V];
			rc = rradc_do_conversion(chip, prop, &adc_code);
			if (rc == -ENODATA) {
				pr_err("rradc is hung, Proceed to recovery\n");
				if (rradc_is_bms_psy_available(chip)) {
					rc = rradc_write_iio_chan(chip,
						RRADC_FG_GEN3_FG_RESET_CLOCK,
						pval.intval);
					if (rc < 0)
						pr_err("Couldn't reset FG clock rc=%d\n",
								rc);
					prop = &chip->chan_props[RR_ADC_BATT_ID];
					rc = rradc_do_conversion(chip, prop,
							&adc_code);
					if (rc == -ENODATA)
						pr_err("RRADC read failed after reset\n");
				} else {
					pr_err("Error obtaining bms power supply\n");
				}
			}
		}
	} else {
		pr_err("Error obtaining battery power supply\n");
	}
	chip->conv_cbk = false;
	pm_relax(chip->dev);
}

static int rradc_psy_notifier_cb(struct notifier_block *nb,
		unsigned long event, void *data)
{
	struct power_supply *psy = data;
	struct rradc_chip *chip = container_of(nb, struct rradc_chip, nb);

	if (strcmp(psy->desc->name, "battery") == 0) {
		pm_stay_awake(chip->dev);
		schedule_work(&chip->psy_notify_work);
	}

	return NOTIFY_OK;
}

static const struct iio_info rradc_info = {
	.read_raw	= &rradc_read_raw,
};

static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node)
{
	const struct rradc_channels *rradc_chan;
	struct iio_chan_spec *iio_chan;
	unsigned int i = 0, base;
	int rc = 0;
	struct rradc_chan_prop prop;

	chip->nchannels = RR_ADC_MAX;
	chip->iio_chans = devm_kcalloc(chip->dev, chip->nchannels,
				       sizeof(*chip->iio_chans), GFP_KERNEL);
	if (!chip->iio_chans)
		return -ENOMEM;

	chip->chan_props = devm_kcalloc(chip->dev, chip->nchannels,
				       sizeof(*chip->chan_props), GFP_KERNEL);
	if (!chip->chan_props)
		return -ENOMEM;

	/* Get the peripheral address */
	rc = of_property_read_u32(node, "reg", &base);
	if (rc < 0) {
		dev_err(chip->dev,
			"Couldn't find reg in node = %s rc = %d\n",
			node->name, rc);
		return rc;
	}

	chip->base = base;
	chip->revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
	if (chip->revid_dev_node) {
		chip->pmic_fab_id = get_revid_data(chip->revid_dev_node);
		if (IS_ERR(chip->pmic_fab_id)) {
			rc = PTR_ERR(chip->pmic_fab_id);
			if (rc != -EPROBE_DEFER)
				pr_err("Unable to get pmic_revid rc=%d\n", rc);
			return rc;
		}

		if (!chip->pmic_fab_id)
			return -EINVAL;

		if (chip->pmic_fab_id->fab_id == -EINVAL) {
			rc = chip->pmic_fab_id->fab_id;
			pr_debug("Unable to read fabid rc=%d\n", rc);
		}
	}

	chip->rradc_fg_reset_wa =
		of_property_read_bool(node, "qcom,rradc-fg-reset-wa");

	iio_chan = chip->iio_chans;

	for (i = 0; i < RR_ADC_MAX; i++) {
		prop.channel = i;
		prop.scale = rradc_chans[i].scale;
		/* Private channel data used for selecting batt_id */
		prop.channel_data = 0;
		chip->chan_props[i] = prop;

		rradc_chan = &rradc_chans[i];

		iio_chan->channel = prop.channel;
		iio_chan->datasheet_name = rradc_chan->datasheet_name;
		iio_chan->extend_name = rradc_chan->datasheet_name;
		iio_chan->info_mask_separate = rradc_chan->info_mask;
		iio_chan->type = rradc_chan->type;
		iio_chan->address = i;
		iio_chan++;
	}

	return 0;
}

static int rradc_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct iio_dev *indio_dev;
	struct rradc_chip *chip;
	int rc = 0;

	indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
	if (!indio_dev)
		return -ENOMEM;

	chip = iio_priv(indio_dev);
	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
	if (!chip->regmap) {
		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
		return -EINVAL;
	}

	chip->dev = dev;
	mutex_init(&chip->lock);

	rc = rradc_get_dt_data(chip, node);
	if (rc)
		return rc;

	indio_dev->dev.parent = dev;
	indio_dev->dev.of_node = node;
	indio_dev->name = pdev->name;
	indio_dev->modes = INDIO_DIRECT_MODE;
	indio_dev->info = &rradc_info;
	indio_dev->channels = chip->iio_chans;
	indio_dev->num_channels = chip->nchannels;

	chip->usb_trig = power_supply_get_by_name("usb");
	if (!chip->usb_trig)
		pr_debug("Error obtaining usb power supply\n");

	if (chip->rradc_fg_reset_wa) {
		chip->nb.notifier_call = rradc_psy_notifier_cb;
		rc = power_supply_reg_notifier(&chip->nb);
		if (rc < 0)
			pr_err("Error registering psy notifier rc = %d\n", rc);

		INIT_WORK(&chip->psy_notify_work, psy_notify_work);
	}

	return devm_iio_device_register(dev, indio_dev);
}

static const struct of_device_id rradc_match_table[] = {
	{ .compatible = "qcom,rradc" },
	{ }
};
MODULE_DEVICE_TABLE(of, rradc_match_table);

static struct platform_driver rradc_driver = {
	.driver		= {
		.name		= "qcom-rradc",
		.of_match_table	= rradc_match_table,
	},
	.probe = rradc_probe,
};
module_platform_driver(rradc_driver);

MODULE_DESCRIPTION("QPNP PMIC RR ADC driver");
MODULE_LICENSE("GPL v2");
