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

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

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

parents 2fc23baf cf60c5f1
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;
}