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

Commit 39b81f8a authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 7c694f62 6db0f9ed
Loading
Loading
Loading
Loading
+131 −5
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2017, 2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -194,6 +194,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
@@ -236,6 +237,11 @@ 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;
	struct work_struct	psy_notify_work;
};

struct rradc_channels {
@@ -680,6 +686,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;
@@ -749,6 +777,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:
@@ -775,7 +804,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) {
@@ -784,8 +817,26 @@ 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))) {
		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;
}
@@ -1073,6 +1124,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");
				} else {
					pr_err("Error obtaining bms power supply");
				}
			}
		}
	} else {
		pr_err("Error obtaining battery power supply");
	}
	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,
	.driver_module	= THIS_MODULE,
@@ -1184,6 +1296,20 @@ static int rradc_probe(struct platform_device *pdev)
	if (!chip->usb_trig)
		pr_debug("Error obtaining usb power supply\n");

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

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

	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);
}