Ejemplo n.º 1
0
/*
 * Perform a masked read-modify-write to a PMIC register only if the new value
 * differs from the value currently in the register.  This removes redundant
 * register writing.
 */
static int qpnp_vreg_masked_read_write(struct qpnp_regulator *vreg, u16 addr,
		u8 val, u8 mask)
{
	int rc;
	u8 reg;

	rc = qpnp_vreg_read(vreg, addr, &reg, 1);
	if (rc) {
		vreg_err(vreg, "read failed; addr=0x%03X, rc=%d\n", addr, rc);
		return rc;
	}

	return qpnp_vreg_masked_write(vreg, addr, val, mask, &reg);
}
static int qpnp_regulator_match(struct qpnp_regulator *vreg)
{
	const struct qpnp_regulator_mapping *mapping;
	struct device_node *node = vreg->spmi_dev->dev.of_node;
	int rc, i;
	u32 type_reg[2], dig_major_rev;
	u8 version[QPNP_COMMON_REG_SUBTYPE - QPNP_COMMON_REG_DIG_MAJOR_REV + 1];
	u8 type, subtype;

	rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_DIG_MAJOR_REV, version,
		ARRAY_SIZE(version));
	if (rc) {
		vreg_err(vreg, "could not read version registers, rc=%d\n", rc);
		return rc;
	}
	dig_major_rev	= version[QPNP_COMMON_REG_DIG_MAJOR_REV
					- QPNP_COMMON_REG_DIG_MAJOR_REV];
	type		= version[QPNP_COMMON_REG_TYPE
					- QPNP_COMMON_REG_DIG_MAJOR_REV];
	subtype		= version[QPNP_COMMON_REG_SUBTYPE
					- QPNP_COMMON_REG_DIG_MAJOR_REV];

	rc = of_property_read_u32_array(node, "qcom,force-type", type_reg, 2);
	if (!rc) {
		type = type_reg[0];
		subtype = type_reg[1];
	}

	rc = -ENODEV;
	for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
		mapping = &supported_regulators[i];
		if (mapping->type == type && mapping->subtype == subtype
		    && mapping->revision_min <= dig_major_rev
		    && mapping->revision_max >= dig_major_rev) {
			vreg->logical_type	= mapping->logical_type;
			vreg->set_points	= mapping->set_points;
			vreg->hpm_min_load	= mapping->hpm_min_load;
			vreg->rdesc.ops		= mapping->ops;
			vreg->rdesc.n_voltages
				= mapping->set_points->n_voltages;
			rc = 0;
			break;
		}
	}

	return rc;
}
Ejemplo n.º 3
0
static int qpnp_regulator_match(struct qpnp_regulator *vreg)
{
	const struct qpnp_regulator_mapping *mapping;
	struct device_node *node = vreg->spmi_dev->dev.of_node;
	int rc, i;
	u8 raw_type[2], type, subtype;
	u32 type_reg[2];

	rc = of_property_read_u32_array(node, "qcom,force-type",
								type_reg, 2);
	if (!rc) {
		type = type_reg[0];
		subtype = type_reg[1];
	} else {
		rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_TYPE, raw_type, 2);
		if (rc) {
			vreg_err(vreg,
				"could not read type register, rc=%d\n", rc);
			return rc;
		}
		type = raw_type[0];
		subtype = raw_type[1];
	}

	rc = -ENODEV;
	for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
		mapping = &supported_regulators[i];
		if (mapping->type == type && mapping->subtype == subtype) {
			vreg->logical_type	= mapping->logical_type;
			vreg->set_points	= mapping->set_points;
			vreg->hpm_min_load	= mapping->hpm_min_load;
			vreg->rdesc.ops		= mapping->ops;
			vreg->rdesc.n_voltages
				= mapping->set_points->n_voltages;
			rc = 0;
			break;
		}
	}

	return rc;
}
Ejemplo n.º 4
0
static int qpnp_regulator_init_registers(struct qpnp_regulator *vreg,
				struct qpnp_regulator_platform_data *pdata)
{
	int rc, i;
	enum qpnp_regulator_logical_type type;
	u8 ctrl_reg[8], reg, mask;

	type = vreg->logical_type;

	rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_VOLTAGE_RANGE,
			    vreg->ctrl_reg, 8);
	if (rc) {
		vreg_err(vreg, "spmi read failed, rc=%d\n", rc);
		return rc;
	}

	for (i = 0; i < ARRAY_SIZE(ctrl_reg); i++)
		ctrl_reg[i] = vreg->ctrl_reg[i];

	/* Set up enable pin control. */
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_VS)
	    && !(pdata->pin_ctrl_enable
			& QPNP_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_ENABLE] &=
			~QPNP_COMMON_ENABLE_FOLLOW_ALL_MASK;
		ctrl_reg[QPNP_COMMON_IDX_ENABLE] |=
		    pdata->pin_ctrl_enable & QPNP_COMMON_ENABLE_FOLLOW_ALL_MASK;
	}

	/* Set up auto mode control. */
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_VS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS)
	    && (pdata->auto_mode_enable != QPNP_REGULATOR_USE_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_AUTO_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
		     (pdata->auto_mode_enable ? QPNP_COMMON_MODE_AUTO_MASK : 0);
	}

	/* Set up mode pin control. */
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	    || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO)
		&& !(pdata->pin_ctrl_hpm
			& QPNP_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_FOLLOW_ALL_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
			pdata->pin_ctrl_hpm & QPNP_COMMON_MODE_FOLLOW_ALL_MASK;
	}

	if (type == QPNP_REGULATOR_LOGICAL_TYPE_VS
	   && !(pdata->pin_ctrl_hpm & QPNP_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_FOLLOW_AWAKE_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
		       pdata->pin_ctrl_hpm & QPNP_COMMON_MODE_FOLLOW_AWAKE_MASK;
	}

	if (type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	    && pdata->bypass_mode_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_BYPASS_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
			(pdata->bypass_mode_enable
				? QPNP_COMMON_MODE_BYPASS_MASK : 0);
	}

	/* Set boost current limit. */
	if (type == QPNP_REGULATOR_LOGICAL_TYPE_BOOST
		&& pdata->boost_current_limit
			!= QPNP_BOOST_CURRENT_LIMIT_HW_DEFAULT) {
		ctrl_reg[QPNP_BOOST_IDX_CURRENT_LIMIT] &=
			~QPNP_BOOST_CURRENT_LIMIT_MASK;
		ctrl_reg[QPNP_BOOST_IDX_CURRENT_LIMIT] |=
		     pdata->boost_current_limit & QPNP_BOOST_CURRENT_LIMIT_MASK;
	}

	/* Write back any control register values that were modified. */
	rc = qpnp_vreg_write_optimized(vreg, QPNP_COMMON_REG_VOLTAGE_RANGE,
		ctrl_reg, vreg->ctrl_reg, 8);
	if (rc) {
		vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
		return rc;
	}

	/* Set pull down. */
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	    || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	    || type == QPNP_REGULATOR_LOGICAL_TYPE_VS)
	    && pdata->pull_down_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		reg = pdata->pull_down_enable
			? QPNP_COMMON_PULL_DOWN_ENABLE_MASK : 0;
		rc = qpnp_vreg_write(vreg, QPNP_COMMON_REG_PULL_DOWN, &reg, 1);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	if (type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS
	    && pdata->pull_down_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		/* FTSMPS has other bits in the pull down control register. */
		reg = pdata->pull_down_enable
			? QPNP_COMMON_PULL_DOWN_ENABLE_MASK : 0;
		rc = qpnp_vreg_masked_read_write(vreg,
			QPNP_COMMON_REG_PULL_DOWN, reg,
			QPNP_COMMON_PULL_DOWN_ENABLE_MASK);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	/* Set soft start for LDO. */
	if (type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	    && pdata->soft_start_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		reg = pdata->soft_start_enable
			? QPNP_LDO_SOFT_START_ENABLE_MASK : 0;
		rc = qpnp_vreg_write(vreg, QPNP_LDO_REG_SOFT_START, &reg, 1);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	/* Set soft start strength and over current protection for VS. */
	if (type == QPNP_REGULATOR_LOGICAL_TYPE_VS) {
		reg = 0;
		mask = 0;
		if (pdata->soft_start_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
			reg |= pdata->soft_start_enable
				? QPNP_VS_SOFT_START_ENABLE_MASK : 0;
			mask |= QPNP_VS_SOFT_START_ENABLE_MASK;
		}
		if (pdata->vs_soft_start_strength
				!= QPNP_VS_SOFT_START_STR_HW_DEFAULT) {
			reg |= pdata->vs_soft_start_strength
				& QPNP_VS_SOFT_START_SEL_MASK;
			mask |= QPNP_VS_SOFT_START_SEL_MASK;
		}
		rc = qpnp_vreg_masked_read_write(vreg, QPNP_VS_REG_SOFT_START,
						 reg, mask);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}

		if (pdata->ocp_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
			reg = pdata->ocp_enable ? QPNP_VS_OCP_ENABLE_MASK : 0;
			rc = qpnp_vreg_write(vreg, QPNP_VS_REG_OCP, &reg, 1);
			if (rc) {
				vreg_err(vreg, "spmi write failed, rc=%d\n",
					rc);
				return rc;
			}
		}
	}

	return rc;
}
static int qpnp_regulator_init_registers(struct qpnp_regulator *vreg,
				struct qpnp_regulator_platform_data *pdata)
{
	int rc, i;
	enum qpnp_regulator_logical_type type;
	u8 ctrl_reg[8], reg, mask;

	type = vreg->logical_type;

	rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_VOLTAGE_RANGE,
			    vreg->ctrl_reg, 8);
	if (rc) {
		vreg_err(vreg, "spmi read failed, rc=%d\n", rc);
		return rc;
	}

	for (i = 0; i < ARRAY_SIZE(ctrl_reg); i++)
		ctrl_reg[i] = vreg->ctrl_reg[i];

	
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_VS)
	    && !(pdata->pin_ctrl_enable
			& QPNP_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_ENABLE] &=
			~QPNP_COMMON_ENABLE_FOLLOW_ALL_MASK;
		ctrl_reg[QPNP_COMMON_IDX_ENABLE] |=
		    pdata->pin_ctrl_enable & QPNP_COMMON_ENABLE_FOLLOW_ALL_MASK;
	}

	
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_VS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS)
	    && (pdata->hpm_enable != QPNP_REGULATOR_USE_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &= ~QPNP_COMMON_MODE_HPM_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
		     (pdata->hpm_enable ? QPNP_COMMON_MODE_HPM_MASK : 0);
	}

	
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_VS
	     || type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS)
	    && (pdata->auto_mode_enable != QPNP_REGULATOR_USE_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_AUTO_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
		     (pdata->auto_mode_enable ? QPNP_COMMON_MODE_AUTO_MASK : 0);
	}

	
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	    || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO)
		&& !(pdata->pin_ctrl_hpm
			& QPNP_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_FOLLOW_ALL_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
			pdata->pin_ctrl_hpm & QPNP_COMMON_MODE_FOLLOW_ALL_MASK;
	}

	if (type == QPNP_REGULATOR_LOGICAL_TYPE_VS
	   && !(pdata->pin_ctrl_hpm & QPNP_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_FOLLOW_AWAKE_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
		       pdata->pin_ctrl_hpm & QPNP_COMMON_MODE_FOLLOW_AWAKE_MASK;
	}

	if (type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	    && pdata->bypass_mode_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		ctrl_reg[QPNP_COMMON_IDX_MODE] &=
			~QPNP_COMMON_MODE_BYPASS_MASK;
		ctrl_reg[QPNP_COMMON_IDX_MODE] |=
			(pdata->bypass_mode_enable
				? QPNP_COMMON_MODE_BYPASS_MASK : 0);
	}

	
	if (type == QPNP_REGULATOR_LOGICAL_TYPE_BOOST
		&& pdata->boost_current_limit
			!= QPNP_BOOST_CURRENT_LIMIT_HW_DEFAULT) {
		reg = pdata->boost_current_limit;
		mask = QPNP_BOOST_CURRENT_LIMIT_MASK;
		rc = qpnp_vreg_masked_read_write(vreg,
			QPNP_BOOST_REG_CURRENT_LIMIT, reg, mask);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	
	rc = qpnp_vreg_write_optimized(vreg, QPNP_COMMON_REG_VOLTAGE_RANGE,
		ctrl_reg, vreg->ctrl_reg, 8);
	if (rc) {
		vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
		return rc;
	}

	
	if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
	    || type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	    || type == QPNP_REGULATOR_LOGICAL_TYPE_VS)
	    && pdata->pull_down_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		reg = pdata->pull_down_enable
			? QPNP_COMMON_PULL_DOWN_ENABLE_MASK : 0;
		rc = qpnp_vreg_write(vreg, QPNP_COMMON_REG_PULL_DOWN, &reg, 1);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	if (type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS
	    && pdata->pull_down_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		
		reg = pdata->pull_down_enable
			? QPNP_COMMON_PULL_DOWN_ENABLE_MASK : 0;
		rc = qpnp_vreg_masked_read_write(vreg,
			QPNP_COMMON_REG_PULL_DOWN, reg,
			QPNP_COMMON_PULL_DOWN_ENABLE_MASK);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	
	if (type == QPNP_REGULATOR_LOGICAL_TYPE_LDO
	    && pdata->soft_start_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
		reg = pdata->soft_start_enable
			? QPNP_LDO_SOFT_START_ENABLE_MASK : 0;
		rc = qpnp_vreg_write(vreg, QPNP_LDO_REG_SOFT_START, &reg, 1);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}
	}

	
	if (type == QPNP_REGULATOR_LOGICAL_TYPE_VS) {
		reg = 0;
		mask = 0;
		if (pdata->soft_start_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
			reg |= pdata->soft_start_enable
				? QPNP_VS_SOFT_START_ENABLE_MASK : 0;
			mask |= QPNP_VS_SOFT_START_ENABLE_MASK;
		}
		if (pdata->vs_soft_start_strength
				!= QPNP_VS_SOFT_START_STR_HW_DEFAULT) {
			reg |= pdata->vs_soft_start_strength
				& QPNP_VS_SOFT_START_SEL_MASK;
			mask |= QPNP_VS_SOFT_START_SEL_MASK;
		}
		rc = qpnp_vreg_masked_read_write(vreg, QPNP_VS_REG_SOFT_START,
						 reg, mask);
		if (rc) {
			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
			return rc;
		}

		if (pdata->ocp_enable != QPNP_REGULATOR_USE_HW_DEFAULT) {
			reg = pdata->ocp_enable ? QPNP_VS_OCP_NO_OVERRIDE
						: QPNP_VS_OCP_OVERRIDE;
			rc = qpnp_vreg_write(vreg, QPNP_VS_REG_OCP, &reg, 1);
			if (rc) {
				vreg_err(vreg, "spmi write failed, rc=%d\n",
					rc);
				return rc;
			}
		}
	}

	return rc;
}