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

Commit 09feab8b authored by Ashay Jaiswal's avatar Ashay Jaiswal Committed by Kiran Gunda
Browse files

power: smb5: Add support for SCHGM_FLASH module



Add support for SCHGM_FLASH module in charger driver.
SCHGM_FLASH module handles flash failure, de-rating and
allows configuration for different flash features.

Change-Id: Iae8db5c1ba9d6cf7ecec960c4d93f22aacd05329
Signed-off-by: default avatarAshay Jaiswal <ashayj@codeaurora.org>
parent c2aa9c2a
Loading
Loading
Loading
Loading
+47 −0
Original line number Original line Diff line number Diff line
@@ -164,6 +164,32 @@ Charger specific properties:
		to be get from these properties defined in battery profile:
		to be get from these properties defined in battery profile:
		qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges.
		qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges.


- qcom,flash-derating-soc
  Usage:      optional
  Value type: <u32>
  Definition: SOC threshold in percentage below which hardware will start
		derating flash. This is only applicable to certain PMICs like
		PMI632 which has SCHGM_FLASH peripheral.

- qcom,flash-disable-soc
  Usage:      optional
  Value type: <u32>
  Definition: SOC threshold in percentage below which hardware will disable
		flash. This is only applicable to certain PMICs like PMI632
		which has SCHGM_FLASH peripheral.

- qcom,headroom-mode
  Usage:      optional
  Value type: <u32>
  Definition: Specifies flash hardware headroom management policy. The
		possible values are:
		<0>: Fixed mode, constant 5V at flash input.
		<1>: Adaptive mode allows charger output voltage to be
		dynamically controlled by the flash module based on the
		required flash headroom.
		This is only applicable to certain PMICs like PMI632 which
		has SCHGM_FLASH peripheral.

=============================================
=============================================
Second Level Nodes - SMB5 Charger Peripherals
Second Level Nodes - SMB5 Charger Peripherals
=============================================
=============================================
@@ -301,4 +327,25 @@ pmi8998_charger: qcom,qpnp-smb5 {
					"temperature-change",
					"temperature-change",
					"switcher-power-ok";
					"switcher-power-ok";
	};
	};

	qcom,schgm-flash@a600 {
		reg = <0xa600 0x100>;
		interrupts =	<0x2 0xa6 0x0 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x1 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x2 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x3 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x4 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x5 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x6 IRQ_TYPE_NONE>,
				<0x2 0xa6 0x7 IRQ_TYPE_NONE>;

		interrupt-names =	"flash-en",
					"torch-req",
					"flash-state-change",
					"vout-up",
					"vout-down",
					"ilim1-s1",
					"ilim2-s2",
					"vreg-ok";
	};
};
};
+1 −1
Original line number Original line Diff line number Diff line
@@ -9,4 +9,4 @@ obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o pm
obj-$(CONFIG_QPNP_QG)		+= qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
obj-$(CONFIG_QPNP_QG)		+= qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
obj-$(CONFIG_QPNP_QNOVO)	+= qpnp-qnovo.o battery.o
obj-$(CONFIG_QPNP_QNOVO)	+= qpnp-qnovo.o battery.o
obj-$(CONFIG_QPNP_TYPEC)	+= qpnp-typec.o
obj-$(CONFIG_QPNP_TYPEC)	+= qpnp-typec.o
obj-$(CONFIG_QPNP_SMB5)		+= step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o
obj-$(CONFIG_QPNP_SMB5)		+= step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
+63 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/pmic-voter.h>
#include <linux/pmic-voter.h>
#include "smb5-reg.h"
#include "smb5-reg.h"
#include "smb5-lib.h"
#include "smb5-lib.h"
#include "schgm-flash.h"


static struct smb_params smb5_pmi632_params = {
static struct smb_params smb5_pmi632_params = {
	.fcc			= {
	.fcc			= {
@@ -371,6 +372,7 @@ static enum power_supply_property smb5_usb_props[] = {
	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
	POWER_SUPPLY_PROP_VOLTAGE_MAX,
	POWER_SUPPLY_PROP_VOLTAGE_MAX,
	POWER_SUPPLY_PROP_SCOPE,
};
};


static int smb5_usb_get_prop(struct power_supply *psy,
static int smb5_usb_get_prop(struct power_supply *psy,
@@ -379,6 +381,7 @@ static int smb5_usb_get_prop(struct power_supply *psy,
{
{
	struct smb5 *chip = power_supply_get_drvdata(psy);
	struct smb5 *chip = power_supply_get_drvdata(psy);
	struct smb_charger *chg = &chip->chg;
	struct smb_charger *chg = &chip->chg;
	union power_supply_propval pval;
	int rc = 0;
	int rc = 0;


	switch (psp) {
	switch (psp) {
@@ -476,6 +479,15 @@ static int smb5_usb_get_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
	case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
		val->intval = chg->connector_type;
		val->intval = chg->connector_type;
		break;
		break;
	case POWER_SUPPLY_PROP_SCOPE:
		val->intval = POWER_SUPPLY_SCOPE_UNKNOWN;
		rc = smblib_get_prop_usb_present(chg, &pval);
		if (rc < 0)
			break;
		val->intval = pval.intval ? POWER_SUPPLY_SCOPE_DEVICE
				: chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM
						: POWER_SUPPLY_SCOPE_UNKNOWN;
		break;
	default:
	default:
		pr_err("get prop %d is not supported in usb\n", psp);
		pr_err("get prop %d is not supported in usb\n", psp);
		rc = -EINVAL;
		rc = -EINVAL;
@@ -701,6 +713,8 @@ static enum power_supply_property smb5_usb_main_props[] = {
	POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
	POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
	POWER_SUPPLY_PROP_FCC_DELTA,
	POWER_SUPPLY_PROP_FCC_DELTA,
	POWER_SUPPLY_PROP_CURRENT_MAX,
	POWER_SUPPLY_PROP_CURRENT_MAX,
	POWER_SUPPLY_PROP_FLASH_ACTIVE,
	POWER_SUPPLY_PROP_FLASH_TRIGGER,
};
};


static int smb5_usb_main_get_prop(struct power_supply *psy,
static int smb5_usb_main_get_prop(struct power_supply *psy,
@@ -734,6 +748,12 @@ static int smb5_usb_main_get_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_CURRENT_MAX:
	case POWER_SUPPLY_PROP_CURRENT_MAX:
		rc = smblib_get_icl_current(chg, &val->intval);
		rc = smblib_get_icl_current(chg, &val->intval);
		break;
		break;
	case POWER_SUPPLY_PROP_FLASH_ACTIVE:
		val->intval = chg->flash_active;
		break;
	case POWER_SUPPLY_PROP_FLASH_TRIGGER:
		rc = schgm_flash_get_vreg_ok(chg, &val->intval);
		break;
	default:
	default:
		pr_debug("get prop %d is not supported in usb-main\n", psp);
		pr_debug("get prop %d is not supported in usb-main\n", psp);
		rc = -EINVAL;
		rc = -EINVAL;
@@ -765,6 +785,9 @@ static int smb5_usb_main_set_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_CURRENT_MAX:
	case POWER_SUPPLY_PROP_CURRENT_MAX:
		rc = smblib_set_icl_current(chg, val->intval);
		rc = smblib_set_icl_current(chg, val->intval);
		break;
		break;
	case POWER_SUPPLY_PROP_FLASH_ACTIVE:
		chg->flash_active = val->intval;
		break;
	default:
	default:
		pr_err("set prop %d is not supported\n", psp);
		pr_err("set prop %d is not supported\n", psp);
		rc = -EINVAL;
		rc = -EINVAL;
@@ -1367,6 +1390,13 @@ static int smb5_init_hw(struct smb5 *chip)
					: POWER_SUPPLY_CONNECTOR_TYPEC;
					: POWER_SUPPLY_CONNECTOR_TYPEC;
	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");


	/*
	 * PMI632 based hw init:
	 * - Initialize flash module for PMI632
	 */
	if (chg->smb_version == PMI632_SUBTYPE)
		schgm_flash_init(chg);

	smblib_rerun_apsd_if_required(chg);
	smblib_rerun_apsd_if_required(chg);


	/* vote 0mA on usb_icl for non battery platforms */
	/* vote 0mA on usb_icl for non battery platforms */
@@ -1829,6 +1859,39 @@ static struct smb_irq_info smb5_irqs[] = {
		.name		= "temp-change-smb",
		.name		= "temp-change-smb",
		.handler	= default_irq_handler,
		.handler	= default_irq_handler,
	},
	},
	/* FLASH */
	[VREG_OK_IRQ] = {
		.name		= "vreg-ok",
		.handler	= schgm_flash_default_irq_handler,
	},
	[ILIM_S2_IRQ] = {
		.name		= "ilim2-s2",
		.handler	= schgm_flash_ilim2_irq_handler,
	},
	[ILIM_S1_IRQ] = {
		.name		= "ilim1-s1",
		.handler	= schgm_flash_default_irq_handler,
	},
	[VOUT_DOWN_IRQ] = {
		.name		= "vout-down",
		.handler	= schgm_flash_default_irq_handler,
	},
	[VOUT_UP_IRQ] = {
		.name		= "vout-up",
		.handler	= schgm_flash_default_irq_handler,
	},
	[FLASH_STATE_CHANGE_IRQ] = {
		.name		= "flash-state-change",
		.handler	= schgm_flash_state_change_irq_handler,
	},
	[TORCH_REQ_IRQ] = {
		.name		= "torch-req",
		.handler	= schgm_flash_default_irq_handler,
	},
	[FLASH_EN_IRQ] = {
		.name		= "flash-en",
		.handler	= schgm_flash_default_irq_handler,
	},
};
};


static int smb5_get_irq_index_byname(const char *irq_name)
static int smb5_get_irq_index_byname(const char *irq_name)
+216 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2018 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#define pr_fmt(fmt) "SCHG-FLASH: %s: " fmt, __func__

#include <linux/device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/power_supply.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/printk.h>
#include <linux/pmic-voter.h>
#include "smb5-lib.h"
#include "schgm-flash.h"

#define IS_BETWEEN(left, right, value) \
		(((left) >= (right) && (left) >= (value) \
			&& (value) >= (right)) \
		|| ((left) <= (right) && (left) <= (value) \
			&& (value) <= (right)))

irqreturn_t schgm_flash_default_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;

	pr_debug("IRQ: %s\n", irq_data->name);

	return IRQ_HANDLED;
}

irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	int rc;

	rc = smblib_write(chg, SCHGM_FLASH_S2_LATCH_RESET_CMD_REG,
				FLASH_S2_LATCH_RESET_BIT);
	if (rc < 0)
		pr_err("Couldn't reset S2_LATCH reset rc=%d\n", rc);

	return IRQ_HANDLED;
}

irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	int rc;
	u8 reg;

	rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &reg);
	if (rc < 0)
		pr_err("Couldn't read flash status_3 rc=%d\n", rc);
	else
		pr_debug("Flash status changed state=[%x]\n",
					(reg && FLASH_STATE_MASK));

	return IRQ_HANDLED;
}

#define FIXED_MODE		0
#define ADAPTIVE_MODE		1
static void schgm_flash_parse_dt(struct smb_charger *chg)
{
	struct device_node *node = chg->dev->of_node;
	u32 val;
	int rc;

	chg->flash_derating_soc = -EINVAL;
	rc = of_property_read_u32(node, "qcom,flash-derating-soc", &val);
	if (!rc) {
		if (IS_BETWEEN(0, 100, val))
			chg->flash_derating_soc = (val * 255) / 100;
	}

	chg->flash_disable_soc = -EINVAL;
	rc = of_property_read_u32(node, "qcom,flash-disable-soc", &val);
	if (!rc) {
		if (IS_BETWEEN(0, 100, val))
			chg->flash_disable_soc = (val * 255) / 100;
	}

	chg->headroom_mode = -EINVAL;
	rc = of_property_read_u32(node, "qcom,headroom-mode", &val);
	if (!rc) {
		if (IS_BETWEEN(FIXED_MODE, ADAPTIVE_MODE, val))
			chg->headroom_mode = val;
	}
}

int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val)
{
	int rc, vreg_state;
	u8 stat = 0;

	if (!chg->flash_init_done)
		return -EPERM;

	rc = smblib_read(chg, SCHGM_FLASH_STATUS_2_REG, &stat);
	if (rc < 0) {
		pr_err("Couldn't read FLASH STATUS_2 rc=%d\n", rc);
		return rc;
	}
	vreg_state = !!(stat & VREG_OK_BIT);

	/* If VREG_OK is not set check for flash error */
	if (!vreg_state) {
		rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &stat);
		if (rc < 0) {
			pr_err("Couldn't read FLASH_STATUS_3 rc=%d\n", rc);
			return rc;
		}
		if ((stat & FLASH_STATE_MASK) == FLASH_ERROR_VAL) {
			vreg_state = -EFAULT;
			rc = smblib_read(chg, SCHGM_FLASH_STATUS_5_REG,
					&stat);
			if (rc < 0) {
				pr_err("Couldn't read FLASH_STATUS_5 rc=%d\n",
						rc);
				return rc;
			}
			pr_debug("Flash error: status=%x\n", stat);
		}
	}

	/*
	 * val can be one of the following:
	 * 1		- VREG_OK is set.
	 * 0		- VREG_OK is 0 but no Flash error.
	 * -EFAULT	- Flash Error is set.
	 */
	*val = vreg_state;

	return 0;
}

int schgm_flash_init(struct smb_charger *chg)
{
	int rc;
	u8 reg;

	schgm_flash_parse_dt(chg);

	if (chg->flash_derating_soc != -EINVAL) {
		rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG,
					chg->flash_derating_soc);
		if (rc < 0) {
			pr_err("Couldn't configure SOC for flash derating rc=%d\n",
					rc);
			return rc;
		}
	}

	if (chg->flash_disable_soc != -EINVAL) {
		rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG,
					chg->flash_disable_soc);
		if (rc < 0) {
			pr_err("Couldn't configure SOC for flash disable rc=%d\n",
					rc);
			return rc;
		}
	}

	if (chg->headroom_mode != -EINVAL) {
		/*
		 * configure headroom management policy for
		 * flash and torch mode.
		 */
		reg = (chg->headroom_mode == FIXED_MODE)
					? FORCE_FLASH_BOOST_5V_BIT : 0;
		rc = smblib_write(chg, SCHGM_FORCE_BOOST_CONTROL, reg);
		if (rc < 0) {
			pr_err("Couldn't write force boost control reg rc=%d\n",
					rc);
			return rc;
		}

		reg = (chg->headroom_mode == FIXED_MODE)
					? TORCH_PRIORITY_CONTROL_BIT : 0;
		rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL, reg);
		if (rc < 0) {
			pr_err("Couldn't force 5V boost in torch mode rc=%d\n",
					rc);
			return rc;
		}
	}

	if ((chg->flash_derating_soc != -EINVAL)
				|| (chg->flash_disable_soc != -EINVAL)) {
		/* Check if SOC based derating/disable is enabled */
		rc = smblib_read(chg, SCHGM_FLASH_CONTROL_REG, &reg);
		if (rc < 0) {
			pr_err("Couldn't read flash control reg rc=%d\n", rc);
			return rc;
		}
		if (!(reg & SOC_LOW_FOR_FLASH_EN_BIT))
			pr_warn("Soc based flash derating not enabled\n");
	}

	chg->flash_init_done = true;

	return 0;
}
+54 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2018 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __SCHGM_FLASH_H__
#define __SCHGM_FLASH_H__

#include <linux/bitops.h>

#define SCHGM_FLASH_BASE			0xA600

#define SCHGM_FLASH_STATUS_2_REG		(SCHGM_FLASH_BASE + 0x07)
#define VREG_OK_BIT				BIT(4)

#define SCHGM_FLASH_STATUS_3_REG		(SCHGM_FLASH_BASE + 0x08)
#define FLASH_STATE_MASK			GENMASK(2, 0)
#define FLASH_ERROR_VAL				0x7

#define SCHGM_FLASH_INT_RT_STS_REG		(SCHGM_FLASH_BASE + 0x10)

#define SCHGM_FLASH_STATUS_5_REG		(SCHGM_FLASH_BASE + 0x0B)

#define SCHGM_FORCE_BOOST_CONTROL		(SCHGM_FLASH_BASE + 0x41)
#define FORCE_FLASH_BOOST_5V_BIT		BIT(0)

#define SCHGM_FLASH_S2_LATCH_RESET_CMD_REG	(SCHGM_FLASH_BASE + 0x44)
#define FLASH_S2_LATCH_RESET_BIT		BIT(0)

#define SCHGM_FLASH_CONTROL_REG			(SCHGM_FLASH_BASE + 0x60)
#define SOC_LOW_FOR_FLASH_EN_BIT		BIT(7)

#define SCHGM_TORCH_PRIORITY_CONTROL		(SCHGM_FLASH_BASE + 0x63)
#define TORCH_PRIORITY_CONTROL_BIT		BIT(0)

#define SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG	(SCHGM_FLASH_BASE + 0x67)

#define SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG \
						(SCHGM_FLASH_BASE + 0x68)

int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val);
int schgm_flash_init(struct smb_charger *chg);

irqreturn_t schgm_flash_default_irq_handler(int irq, void *data);
irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data);
irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data);
#endif /* __SCHGM_FLASH_H__ */
Loading