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

Commit cf60c5f1 authored by Kiran Gunda's avatar Kiran Gunda Committed by Gerrit - the friendly Code Review server
Browse files

regulator: qpnp-lcdb: Add support for LCDB v2 module



LCDB module used in certain new PMICs (PMI632) have some
peripheral register differences and peripheral's major
revision (v2) got updated as well. Add the necessary changes
to support v2 HW.

Change-Id: I785466cb050cd2f4c74e3e0b30c0530765ab3e55
Signed-off-by: default avatarKiran Gunda <kgunda@codeaurora.org>
parent b4695fbf
Loading
Loading
Loading
Loading
+227 −64
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-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
@@ -50,6 +50,8 @@
#define ATTW_MAX_MS			32

#define LCDB_BST_OUTPUT_VOLTAGE_REG	0x41
#define PM660_BST_OUTPUT_VOLTAGE_MASK	GENMASK(4, 0)
#define BST_OUTPUT_VOLTAGE_MASK		GENMASK(5, 0)

#define LCDB_MODULE_RDY_REG		0x45
#define MODULE_RDY_BIT			BIT(7)
@@ -71,7 +73,8 @@

#define LCDB_PS_CTL_REG			0x50
#define EN_PS_BIT			BIT(7)
#define PS_THRESHOLD_MASK		GENMASK(1, 0)
#define PM660_PS_THRESH_MASK		GENMASK(1, 0)
#define PS_THRESH_MASK			GENMASK(2, 0)
#define MIN_BST_PS_MA			50
#define MAX_BST_PS_MA			80

@@ -83,6 +86,20 @@
#define LCDB_BST_VREG_OK_CTL_REG	0x55
#define BST_VREG_OK_DEB_MASK		GENMASK(1, 0)

#define LCDB_BST_SS_CTL_REG		0x5B
#define BST_SS_TIME_MASK		GENMASK(1, 0)
#define BST_PRECHG_SHORT_ALARM_SHIFT	2
#define BST_PRECHARGE_DONE_DEB_BIT	BIT(4)
#define BST_SS_TIME_OVERRIDE_SHIFT	5

#define BST_SS_TIME_OVERRIDE_0MS	0
#define BST_SS_TIME_OVERRIDE_0P5_MS	1
#define BST_SS_TIME_OVERRIDE_1MS	2
#define BST_SS_TIME_OVERRIDE_2MS	3

#define EN_BST_PRECHG_SHORT_ALARM	0
#define DIS_BST_PRECHG_SHORT_ALARM	1

#define LCDB_SOFT_START_CTL_REG		0x5F

#define LCDB_MISC_CTL_REG		0x60
@@ -147,7 +164,8 @@
#define MIN_SOFT_START_US		0
#define MAX_SOFT_START_US		2000

#define BST_HEADROOM_DEFAULT_MV		200
#define PM660_BST_HEADROOM_DEFAULT_MV	200
#define BST_HEADROOM_DEFAULT_MV		150

struct ldo_regulator {
	struct regulator_desc		rdesc;
@@ -222,6 +240,7 @@ struct settings {
	u16	address;
	u8	value;
	bool	sec_access;
	bool	valid;
};

enum lcdb_module {
@@ -262,6 +281,8 @@ enum lcdb_settings_index {
	LCDB_LDO_SOFT_START_CTL,
	LCDB_NCP_PD_CTL,
	LCDB_NCP_SOFT_START_CTL,
	LCDB_BST_SS_CTL,
	LCDB_LDO_VREG_OK_CTL,
	LCDB_SETTING_MAX,
};

@@ -286,10 +307,11 @@ static u32 ncp_ilim_ma[] = {
	810,
};

#define SETTING(_id, _sec_access)		\
#define SETTING(_id, _sec_access, _valid)	\
	[_id] = {				\
		.address = _id##_REG,		\
		.sec_access = _sec_access,	\
		.valid = _valid			\
	}					\

static bool is_between(int value, int min, int max)
@@ -334,13 +356,17 @@ static int qpnp_lcdb_secure_write(struct qpnp_lcdb *lcdb,
{
	int rc;
	u8 val = SECURE_UNLOCK_VALUE;
	u8 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;

	mutex_lock(&lcdb->read_write_mutex);
	rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val);
	if (pmic_subtype == PM660L_SUBTYPE) {
		rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG,
				  val);
		if (rc < 0) {
			pr_err("Failed to unlock register rc=%d\n", rc);
			goto fail_write;
		}
	}
	rc = regmap_write(lcdb->regmap, addr, value);
	if (rc < 0)
		pr_err("Failed to write to addr=0x%02x rc=%d\n", addr, rc);
@@ -397,58 +423,100 @@ static int dump_status_registers(struct qpnp_lcdb *lcdb)
	return rc;
}

static struct settings lcdb_settings_pm660l[] = {
	SETTING(LCDB_BST_PD_CTL, false, true),
	SETTING(LCDB_RDSON_MGMNT, false, true),
	SETTING(LCDB_MISC_CTL, false, true),
	SETTING(LCDB_SOFT_START_CTL, false, true),
	SETTING(LCDB_PFM_CTL, false, true),
	SETTING(LCDB_PWRUP_PWRDN_CTL, true, true),
	SETTING(LCDB_LDO_PD_CTL, false, true),
	SETTING(LCDB_LDO_SOFT_START_CTL, false, true),
	SETTING(LCDB_NCP_PD_CTL, false, true),
	SETTING(LCDB_NCP_SOFT_START_CTL, false, true),
	SETTING(LCDB_BST_SS_CTL, false, false),
	SETTING(LCDB_LDO_VREG_OK_CTL, false, false),
};

/* For PMICs like pmi632/pm855L */
static struct settings lcdb_settings[] = {
	SETTING(LCDB_BST_PD_CTL, false),
	SETTING(LCDB_RDSON_MGMNT, false),
	SETTING(LCDB_MISC_CTL, false),
	SETTING(LCDB_SOFT_START_CTL, false),
	SETTING(LCDB_PFM_CTL, false),
	SETTING(LCDB_PWRUP_PWRDN_CTL, true),
	SETTING(LCDB_LDO_PD_CTL, false),
	SETTING(LCDB_LDO_SOFT_START_CTL, false),
	SETTING(LCDB_NCP_PD_CTL, false),
	SETTING(LCDB_NCP_SOFT_START_CTL, false),
	SETTING(LCDB_BST_PD_CTL, false, true),
	SETTING(LCDB_RDSON_MGMNT, false, false),
	SETTING(LCDB_MISC_CTL, false, false),
	SETTING(LCDB_SOFT_START_CTL, false, false),
	SETTING(LCDB_PFM_CTL, false, false),
	SETTING(LCDB_PWRUP_PWRDN_CTL, false, true),
	SETTING(LCDB_LDO_PD_CTL, false, true),
	SETTING(LCDB_LDO_SOFT_START_CTL, false, true),
	SETTING(LCDB_NCP_PD_CTL, false, true),
	SETTING(LCDB_NCP_SOFT_START_CTL, false, true),
	SETTING(LCDB_BST_SS_CTL, false, true),
	SETTING(LCDB_LDO_VREG_OK_CTL, false, true),
};

static int qpnp_lcdb_save_settings(struct qpnp_lcdb *lcdb)
{
	int i, rc = 0;
	int i, size, rc = 0;
	struct settings *setting;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;

	for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) {
	if (pmic_subtype == PM660L_SUBTYPE) {
		setting = lcdb_settings_pm660l;
		size = ARRAY_SIZE(lcdb_settings_pm660l);
	} else {
		setting = lcdb_settings;
		size = ARRAY_SIZE(lcdb_settings);
	}

	for (i = 0; i < size; i++) {
		if (setting[i].valid) {
			rc = qpnp_lcdb_read(lcdb, lcdb->base +
				lcdb_settings[i].address,
				&lcdb_settings[i].value, 1);
					    setting[i].address,
					    &setting[i].value, 1);
			if (rc < 0) {
				pr_err("Failed to read lcdb register address=%x\n",
						lcdb_settings[i].address);
					setting[i].address);
				return rc;
			}
		}
	}

	return rc;
	return 0;
}

static int qpnp_lcdb_restore_settings(struct qpnp_lcdb *lcdb)
{
	int i, rc = 0;
	int i, size, rc = 0;
	struct settings *setting;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;

	for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) {
		if (lcdb_settings[i].sec_access)
	if (pmic_subtype == PM660L_SUBTYPE) {
		setting = lcdb_settings_pm660l;
		size = ARRAY_SIZE(lcdb_settings_pm660l);
	} else {
		setting = lcdb_settings;
		size = ARRAY_SIZE(lcdb_settings);
	}

	for (i = 0; i < size; i++) {
		if (setting[i].valid) {
			if (setting[i].sec_access)
				rc = qpnp_lcdb_secure_write(lcdb, lcdb->base +
					lcdb_settings[i].address,
					lcdb_settings[i].value);
							    setting[i].address,
							    setting[i].value);
			else
				rc = qpnp_lcdb_write(lcdb, lcdb->base +
					lcdb_settings[i].address,
					&lcdb_settings[i].value, 1);
						     setting[i].address,
						     &setting[i].value, 1);
			if (rc < 0) {
				pr_err("Failed to write register address=%x\n",
						lcdb_settings[i].address);
					     setting[i].address);
				return rc;
			}
		}
	}

	return rc;
	return 0;
}

static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb)
@@ -465,6 +533,77 @@ static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb)
		lcdb->settings_saved = true;
	}

	val = HWEN_RDY_BIT;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
			     &val, 1);
	if (rc < 0) {
		pr_err("Failed to hw_enable lcdb rc= %d\n", rc);
		return rc;
	}

	val = (BST_SS_TIME_OVERRIDE_1MS << BST_SS_TIME_OVERRIDE_SHIFT) |
	      (DIS_BST_PRECHG_SHORT_ALARM << BST_PRECHG_SHORT_ALARM_SHIFT);
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1);
	if (rc < 0)
		return rc;

	val = 0;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_SOFT_START_CTL_REG,
			     &val, 1);
	if (rc < 0)
		return rc;

	val = 0;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_SOFT_START_CTL_REG,
			     &val, 1);
	if (rc < 0)
		return rc;

	val = BOOST_DIS_PULLDOWN_BIT | BOOST_PD_STRENGTH_BIT;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG,
			     &val, 1);
	if (rc < 0)
		return rc;

	val = LDO_DIS_PULLDOWN_BIT | LDO_PD_STRENGTH_BIT;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_PD_CTL_REG,
							&val, 1);
	if (rc < 0)
		return rc;

	val = NCP_DIS_PULLDOWN_BIT | NCP_PD_STRENGTH_BIT;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_PD_CTL_REG,
			     &val, 1);
	if (rc < 0)
		return rc;

	val = 0;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_PWRUP_PWRDN_CTL_REG,
			     &val, 1);
	if (rc < 0)
		return rc;

	val = 0;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_VREG_OK_CTL_REG,
			     &val, 1);

	return rc;
}

static int qpnp_lcdb_ttw_enter_pm660l(struct qpnp_lcdb *lcdb)
{
	int rc;
	u8 val;

	if (!lcdb->settings_saved) {
		rc = qpnp_lcdb_save_settings(lcdb);
		if (rc < 0) {
			pr_err("Failed to save LCDB settings rc=%d\n", rc);
			return rc;
		}
		lcdb->settings_saved = true;
	}

	val = BOOST_DIS_PULLDOWN_BIT;
	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG,
							&val, 1);
@@ -715,12 +854,17 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb)
{
	int rc = 0;
	u8 val;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;

	if (!lcdb->lcdb_enabled)
		return 0;

	if (lcdb->ttw_enable) {
		if (pmic_subtype == PM660L_SUBTYPE)
			rc = qpnp_lcdb_ttw_enter_pm660l(lcdb);
		else
			rc = qpnp_lcdb_ttw_enter(lcdb);

		if (rc < 0) {
			pr_err("Failed to enable TTW mode rc=%d\n", rc);
			return rc;
@@ -859,8 +1003,9 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb,
					int voltage_mv, u8 type)
{
	int rc = 0;
	u8 val = 0;
	u8 val, mask = 0;
	int bst_voltage_mv;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
	struct ldo_regulator *ldo = &lcdb->ldo;
	struct ncp_regulator *ncp = &lcdb->ncp;
	struct bst_params *bst = &lcdb->bst;
@@ -877,10 +1022,11 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb,
	if (bst_voltage_mv != bst->voltage_mv) {
		val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
						VOLTAGE_STEP_50_MV);

		mask = (pmic_subtype == PM660L_SUBTYPE) ?
			PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
		rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
					LCDB_BST_OUTPUT_VOLTAGE_REG,
					SET_OUTPUT_VOLTAGE_MASK, val);
					mask, val);
		if (rc < 0) {
			pr_err("Failed to set boost voltage %d mv rc=%d\n",
				bst_voltage_mv, rc);
@@ -898,7 +1044,8 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb,
					int *voltage_mv)
{
	int rc;
	u8 val = 0;
	u8 val, mask = 0;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;

	rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG,
						&val, 1);
@@ -907,7 +1054,9 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb,
		return rc;
	}

	val &= SET_OUTPUT_VOLTAGE_MASK;
	mask = (pmic_subtype == PM660L_SUBTYPE) ?
		PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
	val &= mask;
	*voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV;

	return 0;
@@ -1369,6 +1518,8 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb)
{
	int rc = 0;
	struct device_node *node = lcdb->bst.node;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
	u16 default_headroom_mv;

	/* Boost PD  configuration */
	lcdb->bst.pd = -EINVAL;
@@ -1402,11 +1553,14 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb)
		return -EINVAL;
	}

	default_headroom_mv = (pmic_subtype == PM660L_SUBTYPE) ?
			       PM660_BST_HEADROOM_DEFAULT_MV :
			       BST_HEADROOM_DEFAULT_MV;
	/* Boost head room configuration */
	of_property_read_u16(node, "qcom,bst-headroom-mv",
					&lcdb->bst.headroom_mv);
	if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV)
		lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
	if (lcdb->bst.headroom_mv < default_headroom_mv)
		lcdb->bst.headroom_mv = default_headroom_mv;

	return 0;
}
@@ -1624,7 +1778,8 @@ static int qpnp_lcdb_init_ncp(struct qpnp_lcdb *lcdb)
static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb)
{
	int rc = 0;
	u8 val = 0;
	u8 val, mask = 0;
	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;

	/* configure parameters only if LCDB is disabled */
	if (!is_lcdb_enabled(lcdb)) {
@@ -1677,13 +1832,13 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb)
		}

		if (lcdb->bst.ps_threshold != -EINVAL) {
			mask = (pmic_subtype == PM660L_SUBTYPE) ?
					PM660_PS_THRESH_MASK : PS_THRESH_MASK;
			val = (lcdb->bst.ps_threshold - MIN_BST_PS_MA) / 10;
			val = (lcdb->bst.ps_threshold & PS_THRESHOLD_MASK) |
								EN_PS_BIT;
			val = (lcdb->bst.ps_threshold & mask) | EN_PS_BIT;
			rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
						LCDB_PS_CTL_REG,
						PS_THRESHOLD_MASK | EN_PS_BIT,
						val);
						mask | EN_PS_BIT, val);
			if (rc < 0) {
				pr_err("Failed to configure BST PS threshold rc=%d",
								rc);
@@ -1706,16 +1861,24 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb)
	}
	lcdb->bst.vreg_ok_dbc_us = dbc_us[val & VREG_OK_DEB_MASK];

	if (pmic_subtype == PM660L_SUBTYPE) {
		rc = qpnp_lcdb_read(lcdb, lcdb->base +
				    LCDB_SOFT_START_CTL_REG, &val, 1);
		if (rc < 0) {
		pr_err("Failed to read ncp_soft_start_ctl rc=%d\n", rc);
			pr_err("Failed to read lcdb_soft_start_ctl rc=%d\n",
									rc);
			return rc;
		}
		lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200;

	if (!lcdb->bst.headroom_mv)
		lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
	} else {
		rc = qpnp_lcdb_read(lcdb, lcdb->base +
				    LCDB_BST_SS_CTL_REG, &val, 1);
		if (rc < 0) {
			pr_err("Failed to read bst_soft_start_ctl rc=%d\n", rc);
			return rc;
		}
		lcdb->bst.soft_start_us = soft_start_us[val & SOFT_START_MASK];
	}

	return 0;
}