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

Commit d64fa8eb authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "iio: qcom-rradc: Update logic to monitor health of RRADC peripheral"

parents 6c90899e 7c5d7965
Loading
Loading
Loading
Loading
+130 −4
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2016-2017, 2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2017, 2020-2021, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) "RRADC: %s: " fmt, __func__
@@ -186,6 +186,7 @@
#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
@@ -228,6 +229,12 @@ struct rradc_chip {
	struct pmic_revid_data		*pmic_fab_id;
	int volt;
	struct power_supply		*usb_trig;
	struct power_supply		*batt_psy;
	struct power_supply		*bms_psy;
	struct notifier_block		nb;
	bool				conv_cbk;
	bool				rradc_fg_reset_wa;
	struct work_struct	psy_notify_work;
};

struct rradc_channels {
@@ -672,6 +679,28 @@ static const struct rradc_channels rradc_chans[] = {
			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;
}

static bool rradc_is_bms_psy_available(struct rradc_chip *chip)
{
	if (!chip->bms_psy)
		chip->bms_psy = power_supply_get_by_name("bms");

	if (!chip->bms_psy)
		return false;

	return true;
}

static int rradc_enable_continuous_mode(struct rradc_chip *chip)
{
	int rc = 0;
@@ -741,6 +770,7 @@ 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:
@@ -766,7 +796,11 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip,
			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) {
@@ -775,8 +809,27 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip,
		}
	}

	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 = power_supply_set_property(chip->bms_psy,
					POWER_SUPPLY_PROP_FG_RESET_CLOCK,
					&pval);
			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;
}
@@ -1088,6 +1141,67 @@ static int rradc_read_raw(struct iio_dev *indio_dev,
	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 = power_supply_set_property
						(chip->bms_psy,
						POWER_SUPPLY_PROP_FG_RESET_CLOCK,
						&pval);
					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,
};
@@ -1140,6 +1254,9 @@ static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node)
		}
	}

	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++) {
@@ -1201,6 +1318,15 @@ static int rradc_probe(struct platform_device *pdev)
	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);
}