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

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

Merge "power: qpnp-charger: add support for external current sensing OVP"

parents ecb7bc41 cba3ed80
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -110,6 +110,8 @@ Parent node optional properties:
					DC and USB OVP FETs. Please note that this should only
					be enabled in board designs with PM8941 which have DC_IN
					and USB_IN connected via a short.
 - qcom,ext-ovp-isns-enable-gpio	External OVP enable GPIO.
 - qcom,ext-ovp-isns-r-ohm			External ISNS OVP resistance in ohm.

Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
+133 −5
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@
#include <linux/alarmtimer.h>
#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/qpnp/pin.h>

/* Interrupt offsets */
#define INT_RT_STS(base)			(base + 0x10)
@@ -392,6 +395,9 @@ struct qpnp_chg_chip {
	struct work_struct		reduce_power_stage_work;
	bool				power_stage_workaround_running;
	bool				power_stage_workaround_enable;
	bool				ext_ovp_ic_gpio_enabled;
	unsigned int			ext_ovp_isns_gpio;
	unsigned int			usb_trim_default;
};

static void
@@ -434,6 +440,81 @@ enum usbin_health {
	USBIN_OVP,
};

static int ext_ovp_isns_present;
module_param(ext_ovp_isns_present, int, 0444);
static int ext_ovp_isns_r;
module_param(ext_ovp_isns_r, int, 0444);

static bool ext_ovp_isns_online;
static long ext_ovp_isns_ua;
#define MAX_CURRENT_LENGTH_9A	10
#define ISNS_CURRENT_RATIO	2500
static int ext_ovp_isns_read(char *buffer, const struct kernel_param *kp)
{
	int rc;
	struct qpnp_vadc_result results;
	struct power_supply *batt_psy = power_supply_get_by_name("battery");
	struct qpnp_chg_chip *chip = container_of(batt_psy,
				struct qpnp_chg_chip, batt_psy);

	if (!ext_ovp_isns_present)
		return 0;

	rc = qpnp_vadc_read(chip->vadc_dev, P_MUX7_1_1, &results);
	if (rc) {
		pr_err("Unable to read vbat rc=%d\n", rc);
		return 0;
	}

	pr_debug("voltage %lld uV, current: %d\n mA", results.physical,
			((int) results.physical /
			 (ext_ovp_isns_r / ISNS_CURRENT_RATIO)));

	return snprintf(buffer, MAX_CURRENT_LENGTH_9A, "%d\n",
			((int)results.physical /
			 (ext_ovp_isns_r / ISNS_CURRENT_RATIO)));
}

static int ext_ovp_isns_enable(const char *val, const struct kernel_param *kp)
{
	int rc;
	struct power_supply *batt_psy = power_supply_get_by_name("battery");
	struct qpnp_chg_chip *chip = container_of(batt_psy,
				struct qpnp_chg_chip, batt_psy);

	rc = param_set_bool(val, kp);
	if (rc) {
		pr_err("Unable to set gpio en: %d\n", rc);
		return rc;
	}

	if (*(bool *)kp->arg) {
		gpio_direction_output(
						chip->ext_ovp_isns_gpio, 1);
		chip->ext_ovp_ic_gpio_enabled = 1;
		pr_debug("enabled GPIO\n");
	} else {
		gpio_direction_output(
						chip->ext_ovp_isns_gpio, 0);
		chip->ext_ovp_ic_gpio_enabled = 0;
		pr_debug("disabled GPIO\n");
	}

	return rc;
}

static struct kernel_param_ops ext_ovp_isns_ops = {
	.get = ext_ovp_isns_read,
};
module_param_cb(ext_ovp_isns_ua, &ext_ovp_isns_ops, &ext_ovp_isns_ua, 0644);

static struct kernel_param_ops ext_ovp_en_ops = {
	.set = ext_ovp_isns_enable,
	.get = param_get_bool,
};
module_param_cb(ext_ovp_isns_online, &ext_ovp_en_ops,
		&ext_ovp_isns_online, 0664);

static inline int
get_bpd(const char *name)
{
@@ -890,6 +971,7 @@ qpnp_chg_iusb_trim_set(struct qpnp_chg_chip *chip, int trim)
	return rc;
}

#define IOVP_USB_WALL_TRSH_MA   150
static int
qpnp_chg_iusbmax_set(struct qpnp_chg_chip *chip, int mA)
{
@@ -1323,7 +1405,13 @@ qpnp_chg_usb_chg_gone_irq_handler(int irq, void *_chip)
	if ((qpnp_chg_is_usb_chg_plugged_in(chip)
			|| qpnp_chg_is_dc_chg_plugged_in(chip))
			&& (usb_sts & CHG_GONE_IRQ)) {
		if (ext_ovp_isns_present) {
			pr_debug("EXT OVP IC ISNS disabled due to ARB WA\n");
			gpio_direction_output(chip->ext_ovp_isns_gpio, 0);
		}

		qpnp_chg_charge_en(chip, 0);

		qpnp_chg_force_run_on_batt(chip, 1);
		schedule_delayed_work(&chip->arb_stop_work,
			msecs_to_jiffies(ARB_STOP_WORK_MS));
@@ -1656,6 +1744,7 @@ qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)

			qpnp_chg_usb_suspend_enable(chip, 0);
			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
			qpnp_chg_iusb_trim_set(chip, chip->usb_trim_default);
			chip->prev_usb_max_ma = -EINVAL;
			chip->aicl_settled = false;
		} else {
@@ -1986,6 +2075,13 @@ qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
			}
			if (chip->parallel_ovp_mode)
				switch_parallel_ovp_mode(chip, 1);

			if (ext_ovp_isns_present &&
					chip->ext_ovp_ic_gpio_enabled) {
				pr_debug("EXT OVP IC ISNS enabled\n");
				gpio_direction_output(
						chip->ext_ovp_isns_gpio, 1);
			}
		} else {
			if (chip->parallel_ovp_mode)
				switch_parallel_ovp_mode(chip, 0);
@@ -2599,12 +2695,18 @@ qpnp_batt_external_power_changed(struct power_supply *psy)
					if (!qpnp_is_dc_higher_prio(chip))
						qpnp_chg_idcmax_set(chip,
							QPNP_CHG_I_MAX_MIN_100);
					if (!ext_ovp_present)
						qpnp_chg_iusbmax_set(chip,
							USB_WALL_THRESHOLD_MA);
					else
					if (unlikely(ext_ovp_present)) {
						qpnp_chg_iusbmax_set(chip,
							OVP_USB_WALL_TRSH_MA);
					} else if (unlikely(
							ext_ovp_isns_present)) {
						qpnp_chg_iusb_trim_set(chip, 0);
						qpnp_chg_iusbmax_set(chip,
							IOVP_USB_WALL_TRSH_MA);
					} else {
						qpnp_chg_iusbmax_set(chip,
							USB_WALL_THRESHOLD_MA);
					}
			} else {
				qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
			}
@@ -3146,6 +3248,12 @@ qpnp_chg_regulator_boost_enable(struct regulator_dev *rdev)

	if (qpnp_chg_is_usb_chg_plugged_in(chip) &&
			(chip->flags & BOOST_FLASH_WA)) {

		if (ext_ovp_isns_present && chip->ext_ovp_ic_gpio_enabled) {
			pr_debug("EXT OVP IC ISNS disabled\n");
			gpio_direction_output(chip->ext_ovp_isns_gpio, 0);
		}

		qpnp_chg_usb_suspend_enable(chip, 1);

		rc = qpnp_chg_masked_write(chip,
@@ -3263,6 +3371,11 @@ qpnp_chg_regulator_boost_disable(struct regulator_dev *rdev)
		qpnp_chg_usb_suspend_enable(chip, 0);
	}

	if (ext_ovp_isns_present && chip->ext_ovp_ic_gpio_enabled) {
		pr_debug("EXT OVP IC ISNS enable\n");
		gpio_direction_output(chip->ext_ovp_isns_gpio, 1);
	}

	return rc;
}

@@ -4832,6 +4945,17 @@ qpnp_charger_read_dt_props(struct qpnp_chg_chip *chip)
	ext_ovp_present = of_property_read_bool(chip->spmi->dev.of_node,
					"qcom,ext-ovp-present");

	/* Check if external IOVP part is configured */
	chip->ext_ovp_isns_gpio = of_get_named_gpio(chip->spmi->dev.of_node,
					"qcom,ext-ovp-isns-enable-gpio", 0);
	if (gpio_is_valid(chip->ext_ovp_isns_gpio)) {
		ext_ovp_isns_present = true;
		rc = of_property_read_u32(chip->spmi->dev.of_node,
				"qcom,ext-ovp-isns-r-ohm", &ext_ovp_isns_r);
		if (rc)
			return rc;
	}

	/* Get the charging-disabled property */
	chip->charging_disabled = of_property_read_bool(chip->spmi->dev.of_node,
					"qcom,charging-disabled");
@@ -4939,6 +5063,9 @@ qpnp_charger_probe(struct spmi_device *spmi)
	if (rc)
		return rc;

	if (ext_ovp_isns_present)
		chip->ext_ovp_ic_gpio_enabled = 0;

	/*
	 * Check if bat_if is set in DT and make sure VADC is present
	 * Also try loading the battery data profile if bat_if exists
@@ -5220,6 +5347,7 @@ qpnp_charger_probe(struct spmi_device *spmi)
		goto unregister_dc_psy;
	}

	chip->usb_trim_default = qpnp_chg_iusb_trim_get(chip);
	qpnp_chg_charge_en(chip, !chip->charging_disabled);
	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
	qpnp_chg_set_appropriate_vddmax(chip);