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

Commit 895a60ef authored by Ashay Jaiswal's avatar Ashay Jaiswal Committed by Gerrit - the friendly Code Review server
Browse files

power: qpnp-charger: add support for external Type-C module



Add support for communication between smbcharger and external Type-C
module.
The smbcharger will query current capability and mode information
from Type-C module for configuring it's input current limit and
updating USB OTG status.

Change-Id: I034a7e6e901b2e730f79432b7a2989c45ccb641f
Signed-off-by: default avatarAshay Jaiswal <ashayj@codeaurora.org>
parent a1898eec
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -284,6 +284,13 @@ Optional Properties:
						battery.
- qcom,vchg_sns-vadc		Phandle of the VADC node.
- qcom,vchg-adc-channel-id	The ADC channel to which the VCHG is routed.
- qcom,external-typec		A boolean property to be used when an external
				USB TypeC module is used with charger.
- qcom,typec-psy-name		The psy name to use for external typec. If
				'qcom,external-typec' is present then this is
				a required property.
- qcom,otg-pinctrl:		A boolean property to be used when OTG enable
				control is configured in pin control mode.

Example:
	qcom,qpnp-smbcharger {
+173 −10
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ struct smbchg_chip {
	/* configuration parameters */
	int				iterm_ma;
	int				usb_max_current_ma;
	int				typec_current_ma;
	int				dc_max_current_ma;
	int				dc_target_current_ma;
	int				cfg_fastchg_current_ma;
@@ -141,6 +142,7 @@ struct smbchg_chip {
	bool				restricted_charging;
	bool				skip_usb_suspend_for_fake_battery;
	bool				hvdcp_not_supported;
	bool				otg_pinctrl;
	u8				original_usbin_allowance;
	struct parallel_usb_cfg		parallel;
	struct delayed_work		parallel_en_work;
@@ -190,6 +192,7 @@ struct smbchg_chip {
	bool				icl_disabled;
	u32				wa_flags;
	int				usb_icl_delta;
	bool				typec_dfp;

	/* jeita and temperature */
	bool				batt_hot;
@@ -232,6 +235,7 @@ struct smbchg_chip {
	struct power_supply		batt_psy;
	struct power_supply		dc_psy;
	struct power_supply		*bms_psy;
	struct power_supply		*typec_psy;
	int				dc_psy_type;
	const char			*bms_psy_name;
	const char			*battery_psy_name;
@@ -308,6 +312,7 @@ enum print_reason {
	PR_PM		= BIT(4),
	PR_MISC		= BIT(5),
	PR_WIPOWER	= BIT(6),
	PR_TYPEC	= BIT(7),
};

enum wake_reason {
@@ -1112,6 +1117,48 @@ static int get_prop_batt_health(struct smbchg_chip *chip)
		return POWER_SUPPLY_HEALTH_GOOD;
}

static void get_property_from_typec(struct smbchg_chip *chip,
				enum power_supply_property property,
				union power_supply_propval *prop)
{
	int rc;

	rc = chip->typec_psy->get_property(chip->typec_psy, property, prop);
	if (rc)
		pr_smb(PR_TYPEC,
			"typec psy doesn't support reading prop %d rc = %d\n",
			property, rc);
}

static void update_typec_status(struct smbchg_chip *chip)
{
	union power_supply_propval type = {0, };
	union power_supply_propval capability = {0, };
	int rc;

	get_property_from_typec(chip, POWER_SUPPLY_PROP_TYPE, &type);
	if (type.intval != POWER_SUPPLY_TYPE_UNKNOWN) {
		get_property_from_typec(chip,
				POWER_SUPPLY_PROP_CURRENT_CAPABILITY,
				&capability);
		chip->typec_current_ma = capability.intval;

		if (!chip->skip_usb_notification) {
			rc = chip->usb_psy->set_property(chip->usb_psy,
				POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
				&capability);
			if (rc)
				pr_err("typec failed to set current max rc=%d\n",
					rc);
			pr_smb(PR_TYPEC, "SMB Type-C mode = %d, current=%d\n",
					type.intval, capability.intval);
		}
	} else {
		pr_smb(PR_TYPEC,
			"typec detection not completed continuing with USB update\n");
	}
}

/*
 * finds the index of the closest value in the array. If there are two that
 * are equally close, the lower index will be returned
@@ -3494,6 +3541,7 @@ static void smbchg_external_power_changed(struct power_supply *psy)
		current_limit = prop.intval / 1000;

	read_usb_type(chip, &usb_type_name, &usb_supply_type);

	if (usb_supply_type != POWER_SUPPLY_TYPE_USB)
		goto  skip_current_for_non_sdp;

@@ -3520,6 +3568,11 @@ static int smbchg_otg_regulator_enable(struct regulator_dev *rdev)
	chip->chg_otg_enabled = true;
	smbchg_icl_loop_disable_check(chip);
	smbchg_otg_pulse_skip_disable(chip, REASON_OTG_ENABLED, true);

	/* If pin control mode then return from here */
	if (chip->otg_pinctrl)
		return rc;

	/* sleep to make sure the pulse skip is actually disabled */
	msleep(20);
	rc = smbchg_masked_write(chip, chip->bat_if_base + CMD_CHG_REG,
@@ -3537,10 +3590,14 @@ static int smbchg_otg_regulator_disable(struct regulator_dev *rdev)
	int rc = 0;
	struct smbchg_chip *chip = rdev_get_drvdata(rdev);

	if (!chip->otg_pinctrl) {
		rc = smbchg_masked_write(chip, chip->bat_if_base + CMD_CHG_REG,
				OTG_EN_BIT, 0);
		if (rc < 0)
		dev_err(chip->dev, "Couldn't disable OTG mode rc=%d\n", rc);
			dev_err(chip->dev, "Couldn't disable OTG mode rc=%d\n",
					rc);
	}

	chip->chg_otg_enabled = false;
	smbchg_otg_pulse_skip_disable(chip, REASON_OTG_ENABLED, false);
	smbchg_icl_loop_disable_check(chip);
@@ -4211,7 +4268,14 @@ static int smbchg_change_usb_supply_type(struct smbchg_chip *chip,
	if (type != POWER_SUPPLY_TYPE_UNKNOWN)
		chip->usb_supply_type = type;

	if (type == POWER_SUPPLY_TYPE_USB)
	/*
	 * Type-C only supports STD(900), MEDIUM(1500) and HIGH(3000) current
	 * modes, skip all BC 1.2 current if external typec is supported.
	 * Note: for SDP supporting current based on USB notifications.
	 */
	if (chip->typec_psy && (type != POWER_SUPPLY_TYPE_USB))
		current_limit_ma = chip->typec_current_ma;
	else if (type == POWER_SUPPLY_TYPE_USB)
		current_limit_ma = DEFAULT_SDP_MA;
	else if (type == POWER_SUPPLY_TYPE_USB)
		current_limit_ma = DEFAULT_SDP_MA;
@@ -4420,6 +4484,9 @@ static void handle_usb_removal(struct smbchg_chip *chip)
	/* Clear the OV detected status set before */
	if (chip->usb_ov_det)
		chip->usb_ov_det = false;
	/* Clear typec current status */
	if (chip->typec_psy)
		chip->typec_current_ma = 0;
	smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN);
	if (!chip->skip_usb_notification) {
		pr_smb(PR_MISC, "setting usb psy present = %d\n",
@@ -4500,6 +4567,8 @@ static void handle_usb_insertion(struct smbchg_chip *chip)
		"inserted type = %d (%s)", usb_supply_type, usb_type_name);

	smbchg_aicl_deglitch_wa_check(chip);
	if (chip->typec_psy)
		update_typec_status(chip);
	smbchg_change_usb_supply_type(chip, usb_supply_type);
	if (!chip->skip_usb_notification) {
		pr_smb(PR_MISC, "setting usb psy present = %d\n",
@@ -5377,6 +5446,46 @@ static int smbchg_dp_dm(struct smbchg_chip *chip, int val)
	return rc;
}

static void update_typec_capability_status(struct smbchg_chip *chip,
					const union power_supply_propval *val)
{
	int rc;

	pr_smb(PR_TYPEC, "typec capability = %dma\n", val->intval);

	if (!chip->skip_usb_notification) {
		rc = chip->usb_psy->set_property(chip->usb_psy,
				POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, val);
		if (rc)
			pr_err("typec failed to set current max rc=%d\n", rc);
	}

	pr_debug("changing ICL from %dma to %dma\n", chip->typec_current_ma,
			val->intval);
	chip->typec_current_ma = val->intval;
	smbchg_change_usb_supply_type(chip, chip->usb_supply_type);
}

static void update_typec_otg_status(struct smbchg_chip *chip, int mode,
					bool force)
{
	pr_smb(PR_TYPEC, "typec mode = %d\n", mode);

	if (mode == POWER_SUPPLY_TYPE_DFP) {
		chip->typec_dfp = true;
		power_supply_set_usb_otg(chip->usb_psy, chip->typec_dfp);
		/* update FG */
		set_property_on_fg(chip, POWER_SUPPLY_PROP_STATUS,
				get_prop_batt_status(chip));
	} else if (force || chip->typec_dfp) {
		chip->typec_dfp = false;
		power_supply_set_usb_otg(chip->usb_psy, chip->typec_dfp);
		/* update FG */
		set_property_on_fg(chip, POWER_SUPPLY_PROP_STATUS,
				get_prop_batt_status(chip));
	}
}

#define CHARGE_OUTPUT_VTG_RATIO		840
static int smbchg_get_iusb(struct smbchg_chip *chip)
{
@@ -5488,6 +5597,14 @@ static int smbchg_battery_set_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_RESTRICTED_CHARGING:
		rc = smbchg_restricted_charging(chip, val->intval);
		break;
	case POWER_SUPPLY_PROP_CURRENT_CAPABILITY:
		if (chip->typec_psy)
			update_typec_capability_status(chip, val);
		break;
	case POWER_SUPPLY_PROP_TYPEC_MODE:
		if (chip->typec_psy)
			update_typec_otg_status(chip, val->intval, false);
		break;
	default:
		return -EINVAL;
	}
@@ -6257,6 +6374,8 @@ static irqreturn_t usbid_change_handler(int irq, void *_chip)

static int determine_initial_status(struct smbchg_chip *chip)
{
	union power_supply_propval type = {0, };

	/*
	 * It is okay to read the interrupt status here since
	 * interrupts aren't requested. reading interrupt status
@@ -6270,7 +6389,12 @@ static int determine_initial_status(struct smbchg_chip *chip)
	batt_cool_handler(0, chip);
	batt_cold_handler(0, chip);
	chg_term_handler(0, chip);
	if (chip->typec_psy) {
		get_property_from_typec(chip, POWER_SUPPLY_PROP_TYPE, &type);
		update_typec_otg_status(chip, type.intval, true);
	} else {
		usbid_change_handler(0, chip);
	}
	src_detect_handler(0, chip);

	chip->usb_present = is_usb_present(chip);
@@ -6375,8 +6499,13 @@ static inline int get_bpd(const char *name)
#define HVDCP_AUTH_ALG_EN_BIT		BIT(6)
#define CMD_APSD			0x41
#define APSD_RERUN_BIT			BIT(0)
#define OTG_OC_CFG			0xF1
#define OTG_CFG				0xF1
#define HICCUP_ENABLED_BIT		BIT(6)
#define OTG_PIN_POLARITY_BIT		BIT(4)
#define OTG_PIN_ACTIVE_LOW		BIT(4)
#define OTG_EN_CTRL_MASK		SMB_MASK(3, 2)
#define OTG_PIN_CTRL_RID_DIS		0x04
#define OTG_CMD_CTRL_RID_EN		0x08
#define AICL_ADC_BIT			BIT(6)
static void batt_ov_wa_check(struct smbchg_chip *chip)
{
@@ -6800,13 +6929,25 @@ static int smbchg_hw_init(struct smbchg_chip *chip)

	if (chip->schg_version == QPNP_SCHG_LITE) {
		/* enable OTG hiccup mode */
		rc = smbchg_sec_masked_write(chip, chip->otg_base + OTG_OC_CFG,
		rc = smbchg_sec_masked_write(chip, chip->otg_base + OTG_CFG,
					HICCUP_ENABLED_BIT, HICCUP_ENABLED_BIT);
		if (rc < 0)
			dev_err(chip->dev, "Couldn't set OTG OC config rc = %d\n",
				rc);
	}

	if (chip->otg_pinctrl) {
		/* configure OTG enable to pin control active low */
		rc = smbchg_sec_masked_write(chip, chip->otg_base + OTG_CFG,
				OTG_PIN_POLARITY_BIT | OTG_EN_CTRL_MASK,
				OTG_PIN_ACTIVE_LOW | OTG_PIN_CTRL_RID_DIS);
		if (rc < 0) {
			dev_err(chip->dev, "Couldn't set OTG EN config rc = %d\n",
				rc);
			return rc;
		}
	}

	if (chip->wa_flags & SMBCHG_BATT_OV_WA)
		batt_ov_wa_check(chip);

@@ -7133,6 +7274,9 @@ static int smb_parse_dt(struct smbchg_chip *chip)
	chip->skip_usb_notification
		= of_property_read_bool(node,
				"qcom,skip-usb-notification");

	chip->otg_pinctrl = of_property_read_bool(node, "qcom,otg-pinctrl");

	return 0;
}

@@ -7552,7 +7696,6 @@ static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip)
		fake_insertion_removal(chip, true);

		read_usb_type(chip, &usb_type_name, &usb_supply_type);

		if (usb_supply_type != POWER_SUPPLY_TYPE_USB_DCP) {
			msleep(500);
			pr_smb(PR_STATUS, "Fake Removal again as type!=DCP\n");
@@ -7574,8 +7717,9 @@ static int smbchg_probe(struct spmi_device *spmi)
{
	int rc;
	struct smbchg_chip *chip;
	struct power_supply *usb_psy;
	struct power_supply *usb_psy, *typec_psy = NULL;
	struct qpnp_vadc_chip *vadc_dev, *vchg_vadc_dev;
	const char *typec_psy_name;

	usb_psy = power_supply_get_by_name("usb");
	if (!usb_psy) {
@@ -7583,6 +7727,24 @@ static int smbchg_probe(struct spmi_device *spmi)
		return -EPROBE_DEFER;
	}

	if (of_property_read_bool(spmi->dev.of_node, "qcom,external-typec")) {
		/* read the type power supply name */
		rc = of_property_read_string(spmi->dev.of_node,
				"qcom,typec-psy-name", &typec_psy_name);
		if (rc) {
			pr_err("failed to get prop typec-psy-name rc=%d\n",
				rc);
			return rc;
		}

		typec_psy = power_supply_get_by_name(typec_psy_name);
		if (!typec_psy) {
			pr_smb(PR_STATUS,
				"Type-C supply not found, deferring probe\n");
			return -EPROBE_DEFER;
		}
	}

	if (of_find_property(spmi->dev.of_node, "qcom,dcin-vadc", NULL)) {
		vadc_dev = qpnp_get_vadc(&spmi->dev, "dcin");
		if (IS_ERR(vadc_dev)) {
@@ -7688,6 +7850,7 @@ static int smbchg_probe(struct spmi_device *spmi)
	chip->spmi = spmi;
	chip->dev = &spmi->dev;
	chip->usb_psy = usb_psy;
	chip->typec_psy = typec_psy;
	chip->fake_battery_soc = -EINVAL;
	chip->usb_online = -EINVAL;
	dev_set_drvdata(&spmi->dev, chip);