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

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

Merge "power: smb1360: Add logic to update the battery profile"

parents e0664be7 4fec447b
Loading
Loading
Loading
Loading
+22 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,19 @@ Optional Properties:
				signal when interrupt happened. If this property is not specified,
				signal when interrupt happened. If this property is not specified,
				the default configuration is static level irq.
				the default configuration is static level irq.
- qcom,shdn-after-pwroff:	A bool property to configure smb1360 for shutdown at power-off.
- qcom,shdn-after-pwroff:	A bool property to configure smb1360 for shutdown at power-off.
- qcom,batt-profile-select	A boolean flag to indicate of battery-profile
				selection is enabled.
- qcom,profile-a-rid-kohm	The battery-ID resistor (RID) in Kohm supported by
				profile-A of SMB1360. This should be specified
				if 'batt-profile-select' is defined.
- qcom,profile-b-rid-kohm	The battery-ID resistor (RID) in Kohm supported by
				profile-B of SMB1360. This should be specified
				if 'batt-profile-select' is defined.
- qcom,batt-id-vref-uv		The reference voltage on the battery-ID line
				specified in micro-volts.
- qcom,batt-id-rpullup-kohm	The pull-up resistor connected on the battery-ID
				(vref) line.
- qcom,smb1360-vadc		VADC device phandle (used for reading the RID)


Example:
Example:
	i2c@f9967000 {
	i2c@f9967000 {
@@ -69,6 +82,15 @@ Example:
			interrupts = <0x00 0xcd 0>;
			interrupts = <0x00 0xcd 0>;
			pinctrl-names = "default";
			pinctrl-names = "default";
			pinctrl-0 = <&smb_int_default>;
			pinctrl-0 = <&smb_int_default>;

			/* battery-profile selection properties */
			qcom,batt-profile-select;
			qcom,smb1360-vadc = <&pm8916_vadc>;
			qcom,batt-id-vref-uv = <1800000>;
			qcom,batt-id-rpullup-kohm = <100>;
			qcom,profile-a-rid-kohm = <78>;
			qcom,profile-b-rid-kohm = <200>;

			qcom,float-voltage-mv = <4200>;
			qcom,float-voltage-mv = <4200>;
			qcom,iterm-ma = <100>;
			qcom,iterm-ma = <100>;
			qcom,charging-disabled;
			qcom,charging-disabled;
+271 −7
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/power_supply.h>
#include <linux/power_supply.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/driver.h>
@@ -26,6 +27,7 @@
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_gpio.h>
#include <linux/bitops.h>
#include <linux/bitops.h>
#include <linux/qpnp/qpnp-adc.h>


#define _SMB1360_MASK(BITS, POS) \
#define _SMB1360_MASK(BITS, POS) \
	((unsigned char)(((1 << (BITS)) - 1) << (POS)))
	((unsigned char)(((1 << (BITS)) - 1) << (POS)))
@@ -78,6 +80,9 @@
#define BATT_ID_ENABLED_BIT		BIT(5)
#define BATT_ID_ENABLED_BIT		BIT(5)
#define CHG_BATT_ID_FAIL		BIT(4)
#define CHG_BATT_ID_FAIL		BIT(4)
#define BATT_ID_FAIL_SELECT_PROFILE	BIT(3)
#define BATT_ID_FAIL_SELECT_PROFILE	BIT(3)
#define BATT_PROFILE_SELECT_MASK	SMB1360_MASK(3, 0)
#define BATT_PROFILEA_MASK		0x0
#define BATT_PROFILEB_MASK		0xF


#define IRQ_CFG_REG			0x0F
#define IRQ_CFG_REG			0x0F
#define IRQ_BAT_HOT_COLD_HARD_BIT	BIT(7)
#define IRQ_BAT_HOT_COLD_HARD_BIT	BIT(7)
@@ -114,6 +119,8 @@
/* Command Registers */
/* Command Registers */
#define CMD_I2C_REG			0x40
#define CMD_I2C_REG			0x40
#define ALLOW_VOLATILE_BIT		BIT(6)
#define ALLOW_VOLATILE_BIT		BIT(6)
#define FG_ACCESS_ENABLED_BIT		BIT(5)
#define FG_RESET_BIT			BIT(4)


#define CMD_IL_REG			0x41
#define CMD_IL_REG			0x41
#define USB_CTRL_MASK			SMB1360_MASK(1 , 0)
#define USB_CTRL_MASK			SMB1360_MASK(1 , 0)
@@ -164,6 +171,9 @@


#define IRQ_H_REG			0x57
#define IRQ_H_REG			0x57
#define IRQ_I_REG			0x58
#define IRQ_I_REG			0x58
#define FG_ACCESS_ALLOWED_BIT		BIT(0)
#define BATT_ID_RESULT_BIT		SMB1360_MASK(6, 4)
#define BATT_ID_SHIFT			4


/* FG registers - IRQ config register */
/* FG registers - IRQ config register */
#define SOC_MAX_REG			0x24
#define SOC_MAX_REG			0x24
@@ -174,6 +184,9 @@


/* FG SHADOW registers */
/* FG SHADOW registers */
#define SHDW_FG_ESR_ACTUAL		0x20
#define SHDW_FG_ESR_ACTUAL		0x20
#define SHDW_FG_BATT_STATUS		0x60
#define BATTERY_PROFILE_BIT		BIT(0)

#define SHDW_FG_MSYS_SOC		0x61
#define SHDW_FG_MSYS_SOC		0x61
#define SHDW_FG_CAPACITY		0x62
#define SHDW_FG_CAPACITY		0x62
#define SHDW_FG_VTG_NOW			0x69
#define SHDW_FG_VTG_NOW			0x69
@@ -208,6 +221,12 @@ enum fg_i2c_access_type {
	FG_ACCESS_PROFILE_B = 0x3
	FG_ACCESS_PROFILE_B = 0x3
};
};


enum {
	BATTERY_PROFILE_A,
	BATTERY_PROFILE_B,
	BATTERY_PROFILE_MAX,
};

struct smb1360_otg_regulator {
struct smb1360_otg_regulator {
	struct regulator_desc	rdesc;
	struct regulator_desc	rdesc;
	struct regulator_dev	*rdev;
	struct regulator_dev	*rdev;
@@ -233,6 +252,7 @@ struct smb1360_chip {
	int				vfloat_mv;
	int				vfloat_mv;
	int				safety_time;
	int				safety_time;
	int				resume_delta_mv;
	int				resume_delta_mv;
	u32				default_batt_profile;
	unsigned int			thermal_levels;
	unsigned int			thermal_levels;
	unsigned int			therm_lvl_sel;
	unsigned int			therm_lvl_sel;
	unsigned int			*thermal_mitigation;
	unsigned int			*thermal_mitigation;
@@ -259,6 +279,8 @@ struct smb1360_chip {
	u8				irq_cfg_mask[3];
	u8				irq_cfg_mask[3];
	int				usb_psy_ma;
	int				usb_psy_ma;
	int				charging_disabled_status;
	int				charging_disabled_status;
	u32				connected_rid;
	u32				profile_rid[BATTERY_PROFILE_MAX];


	u32				peek_poke_address;
	u32				peek_poke_address;
	u32				fg_access_type;
	u32				fg_access_type;
@@ -267,6 +289,7 @@ struct smb1360_chip {
	int				skip_reads;
	int				skip_reads;
	struct dentry			*debug_root;
	struct dentry			*debug_root;


	struct qpnp_vadc_chip		*vadc_dev;
	struct power_supply		*usb_psy;
	struct power_supply		*usb_psy;
	struct power_supply		batt_psy;
	struct power_supply		batt_psy;
	struct smb1360_otg_regulator	otg_vreg;
	struct smb1360_otg_regulator	otg_vreg;
@@ -1261,6 +1284,14 @@ static int fg_access_allowed_handler(struct smb1360_chip *chip, u8 rt_stat)
	return 0;
	return 0;
}
}


static int batt_id_complete_handler(struct smb1360_chip *chip, u8 rt_stat)
{
	pr_debug("batt_id = %x\n", (rt_stat & BATT_ID_RESULT_BIT)
						>> BATT_ID_SHIFT);

	return 0;
}

struct smb_irq_info {
struct smb_irq_info {
	const char		*name;
	const char		*name;
	int			(*smb_irq)(struct smb1360_chip *chip,
	int			(*smb_irq)(struct smb1360_chip *chip,
@@ -1429,11 +1460,9 @@ static struct irq_handler_info handlers[] = {
			{
			{
				.name		= "fg_data_recovery",
				.name		= "fg_data_recovery",
			},
			},
			{
				.name		= "batt_id_result",
			},
			{
			{
				.name		= "batt_id_complete",
				.name		= "batt_id_complete",
				.smb_irq	= batt_id_complete_handler,
			},
			},
		},
		},
	},
	},
@@ -1441,6 +1470,8 @@ static struct irq_handler_info handlers[] = {


#define IRQ_LATCHED_MASK	0x02
#define IRQ_LATCHED_MASK	0x02
#define IRQ_STATUS_MASK		0x01
#define IRQ_STATUS_MASK		0x01
#define BATT_ID_LATCHED_MASK	0x08
#define BATT_ID_STATUS_MASK	0x07
#define BITS_PER_IRQ		2
#define BITS_PER_IRQ		2
static irqreturn_t smb1360_stat_handler(int irq, void *dev_id)
static irqreturn_t smb1360_stat_handler(int irq, void *dev_id)
{
{
@@ -1448,7 +1479,7 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id)
	int i, j;
	int i, j;
	u8 triggered;
	u8 triggered;
	u8 changed;
	u8 changed;
	u8 rt_stat, prev_rt_stat;
	u8 rt_stat, prev_rt_stat, irq_latched_mask, irq_status_mask;
	int rc;
	int rc;
	int handler_count = 0;
	int handler_count = 0;


@@ -1472,12 +1503,19 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id)
		}
		}


		for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) {
		for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) {
			if (handlers[i].stat_reg == IRQ_I_REG && j == 2) {
				irq_latched_mask = BATT_ID_LATCHED_MASK;
				irq_status_mask = BATT_ID_STATUS_MASK;
			} else {
				irq_latched_mask = IRQ_LATCHED_MASK;
				irq_status_mask = IRQ_STATUS_MASK;
			}
			triggered = handlers[i].val
			triggered = handlers[i].val
			       & (IRQ_LATCHED_MASK << (j * BITS_PER_IRQ));
			       & (irq_latched_mask << (j * BITS_PER_IRQ));
			rt_stat = handlers[i].val
			rt_stat = handlers[i].val
				& (IRQ_STATUS_MASK << (j * BITS_PER_IRQ));
				& (irq_status_mask << (j * BITS_PER_IRQ));
			prev_rt_stat = handlers[i].prev_val
			prev_rt_stat = handlers[i].prev_val
				& (IRQ_STATUS_MASK << (j * BITS_PER_IRQ));
				& (irq_status_mask << (j * BITS_PER_IRQ));
			changed = prev_rt_stat ^ rt_stat;
			changed = prev_rt_stat ^ rt_stat;


			if (triggered || changed)
			if (triggered || changed)
@@ -1513,6 +1551,8 @@ static int show_irq_count(struct seq_file *m, void *data)


	for (i = 0; i < ARRAY_SIZE(handlers); i++)
	for (i = 0; i < ARRAY_SIZE(handlers); i++)
		for (j = 0; j < 4; j++) {
		for (j = 0; j < 4; j++) {
			if (!handlers[i].irq_info[j].name)
				continue;
			seq_printf(m, "%s=%d\t(high=%d low=%d)\n",
			seq_printf(m, "%s=%d\t(high=%d low=%d)\n",
						handlers[i].irq_info[j].name,
						handlers[i].irq_info[j].name,
						handlers[i].irq_info[j].high
						handlers[i].irq_info[j].high
@@ -1902,6 +1942,144 @@ static int smb1360_regulator_init(struct smb1360_chip *chip)
	return rc;
	return rc;
}
}


static int smb1360_check_batt_profile(struct smb1360_chip *chip)
{
	int rc, i, timeout = 50;
	u8 reg = 0, loaded_profile, new_profile = 0, bid_mask;

	if (!chip->connected_rid) {
		pr_debug("Skip batt-profile loading connected_rid=%d\n",
						chip->connected_rid);
		return 0;
	}

	rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, &reg);
	if (rc) {
		pr_err("Couldn't read FG_BATT_STATUS rc=%d\n", rc);
		goto fail_profile;
	}

	loaded_profile = !!(reg & BATTERY_PROFILE_BIT) ?
			BATTERY_PROFILE_B : BATTERY_PROFILE_A;

	pr_debug("fg_batt_status=%x loaded_profile=%d\n", reg, loaded_profile);

	for (i = 0; i < BATTERY_PROFILE_MAX; i++) {
		pr_debug("profile=%d profile_rid=%d connected_rid=%d\n", i,
						chip->profile_rid[i],
						chip->connected_rid);
		if (abs(chip->profile_rid[i] - chip->connected_rid) <
				(div_u64(chip->connected_rid, 10)))
			break;
	}

	if (i == BATTERY_PROFILE_MAX) {
		pr_err("None of the battery-profiles match the connected-RID\n");
		return 0;
	} else {
		if (i == loaded_profile) {
			pr_debug("Loaded Profile-RID == connected-RID\n");
			return 0;
		} else {
			new_profile = (loaded_profile == BATTERY_PROFILE_A) ?
					BATTERY_PROFILE_B : BATTERY_PROFILE_A;
			bid_mask = (new_profile == BATTERY_PROFILE_A) ?
					BATT_PROFILEA_MASK : BATT_PROFILEB_MASK;
			pr_info("Loaded Profile-RID != connected-RID, switch-profile old_profile=%d new_profile=%d\n",
						loaded_profile, new_profile);
		}
	}

	/* set the BID mask */
	rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG,
				BATT_PROFILE_SELECT_MASK, bid_mask);
	if (rc) {
		pr_err("Couldn't reset battery-profile rc=%d\n", rc);
		goto fail_profile;
	}

	/* enable FG access */
	rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT,
							FG_ACCESS_ENABLED_BIT);
	if (rc) {
		pr_err("Couldn't enable FG access rc=%d\n", rc);
		goto fail_profile;
	}

	while (timeout) {
		/* delay for FG access to be granted */
		msleep(100);
		rc = smb1360_read(chip, IRQ_I_REG, &reg);
		if (rc) {
			pr_err("Could't read IRQ_I_REG rc=%d\n", rc);
			goto restore_fg;
		}
		if (reg & FG_ACCESS_ALLOWED_BIT)
			break;
		timeout--;
	}
	if (!timeout) {
		pr_err("FG access timed-out\n");
		rc = -EAGAIN;
		goto restore_fg;
	}

	/* delay after handshaking for profile-switch to continue */
	msleep(1500);

	/* reset FG */
	rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT,
						FG_RESET_BIT);
	if (rc) {
		pr_err("Couldn't reset FG rc=%d\n", rc);
		goto restore_fg;
	}

	/* un-reset FG */
	rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, 0);
	if (rc) {
		pr_err("Couldn't un-reset FG rc=%d\n", rc);
		goto restore_fg;
	}

	/*  disable FG access */
	rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0);
	if (rc) {
		pr_err("Couldn't disable FG access rc=%d\n", rc);
		goto restore_fg;
	}

	timeout = 10;
	while (timeout) {
		/* delay for profile to change */
		msleep(500);
		rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, &reg);
		if (rc) {
			pr_err("Could't read FG_BATT_STATUS rc=%d\n", rc);
			goto restore_fg;
		}

		reg = !!(reg & BATTERY_PROFILE_BIT);
		if (reg == new_profile) {
			pr_info("New profile=%d loaded\n", new_profile);
			break;
		}
		timeout--;
	}

	if (!timeout) {
		pr_err("New profile could not be loaded\n");
		return -EBUSY;
	}

	return 0;

restore_fg:
	smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0);
fail_profile:
	return rc;
}

static int determine_initial_status(struct smb1360_chip *chip)
static int determine_initial_status(struct smb1360_chip *chip)
{
{
	int rc;
	int rc;
@@ -2125,6 +2303,11 @@ static int smb1360_hw_init(struct smb1360_chip *chip)
			return rc;
			return rc;
		}
		}
	}
	}

	rc = smb1360_check_batt_profile(chip);
	if (rc)
		pr_err("Unable to modify battery profile\n");

	/*
	/*
	 * set chg en by cmd register, set chg en by writing bit 1,
	 * set chg en by cmd register, set chg en by writing bit 1,
	 * enable auto pre to fast
	 * enable auto pre to fast
@@ -2367,6 +2550,78 @@ static int smb1360_hw_init(struct smb1360_chip *chip)
	return rc;
	return rc;
}
}


static int smb_parse_batt_id(struct smb1360_chip *chip)
{
	int rc = 0, rpull = 0, vref = 0;
	int64_t denom, batt_id_uv;
	struct device_node *node = chip->dev->of_node;
	struct qpnp_vadc_result result;

	chip->vadc_dev = qpnp_get_vadc(chip->dev, "smb1360");
	if (IS_ERR(chip->vadc_dev)) {
		rc = PTR_ERR(chip->vadc_dev);
		if (rc == -EPROBE_DEFER)
			pr_err("vadc not found - defer rc=%d\n", rc);
		else
			pr_err("vadc property missing, rc=%d\n", rc);

		return rc;
	}

	rc = of_property_read_u32(node, "qcom,profile-a-rid-kohm",
						&chip->profile_rid[0]);
	if (rc < 0) {
		pr_err("Couldn't read profile-a-rid-kohm rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,profile-b-rid-kohm",
						&chip->profile_rid[1]);
	if (rc < 0) {
		pr_err("Couldn't read profile-b-rid-kohm rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,batt-id-vref-uv", &vref);
	if (rc < 0) {
		pr_err("Couldn't read batt-id-vref-uv rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,batt-id-rpullup-kohm", &rpull);
	if (rc < 0) {
		pr_err("Couldn't read batt-id-rpullup-kohm rc=%d\n", rc);
		return rc;
	}

	/* read battery ID */
	rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result);
	if (rc) {
		pr_err("error reading batt id channel = %d, rc = %d\n",
					LR_MUX2_BAT_ID, rc);
		return rc;
	}
	batt_id_uv = result.physical;

	if (batt_id_uv == 0) {
		/* vadc not correct or batt id line grounded, report 0 kohms */
		pr_err("batt_id_uv = 0, batt-id grounded using same profile\n");
		return 0;
	}

	denom = div64_s64(vref * 1000000LL, batt_id_uv) - 1000000LL;
	if (denom == 0) {
		/* batt id connector might be open, return 0 kohms */
		return 0;
	}
	chip->connected_rid = div64_s64(rpull * 1000000LL + denom/2, denom);

	pr_debug("batt_id_voltage = %lld, connected_rid = %d\n",
			batt_id_uv, chip->connected_rid);

	return 0;
}

static int smb_parse_dt(struct smb1360_chip *chip)
static int smb_parse_dt(struct smb1360_chip *chip)
{
{
	int rc;
	int rc;
@@ -2377,6 +2632,15 @@ static int smb_parse_dt(struct smb1360_chip *chip)
		return -EINVAL;
		return -EINVAL;
	}
	}


	if (of_property_read_bool(node, "qcom,batt-profile-select")) {
		rc = smb_parse_batt_id(chip);
		if (rc < 0) {
			if (rc != -EPROBE_DEFER)
				pr_err("Unable to parse batt-id rc=%d\n", rc);
			return rc;
		}
	}

	chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq");
	chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq");


	rc = of_property_read_u32(node, "qcom,float-voltage-mv",
	rc = of_property_read_u32(node, "qcom,float-voltage-mv",