Commit 0c893564 authored by Amit Sunil Dhamne's avatar Amit Sunil Dhamne Committed by Greg Kroah-Hartman
Browse files

usb: typec: tcpm/tcpci_maxim: deprecate WAR for setting charger mode



TCPCI maxim driver directly writes to the charger's register space to
set charger mode depending on the power role. As MAX77759 chg driver
exists, this WAR is not required.

Instead, use a regulator interface to source vbus when typec is in
source power mode. In other power modes, this regulator will be turned
off if active.

Signed-off-by: default avatarAmit Sunil Dhamne <amitsd@google.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: default avatarAndré Draszik <andre.draszik@linaro.org>
Link: https://patch.msgid.link/20260325-max77759-charger-v9-6-4486dd297adc@google.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 70d7dd27
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ struct max_tcpci_chip {
	struct tcpm_port *port;
	enum contamiant_state contaminant_state;
	bool veto_vconn_swap;
	struct regulator *vbus_reg;
};

static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
+33 −21
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/pd.h>
#include <linux/usb/tcpci.h>
#include <linux/usb/tcpm.h>
@@ -35,12 +36,6 @@
 */
#define TCPC_RECEIVE_BUFFER_LEN				32

#define MAX_BUCK_BOOST_SID				0x69
#define MAX_BUCK_BOOST_OP				0xb9
#define MAX_BUCK_BOOST_OFF				0
#define MAX_BUCK_BOOST_SOURCE				0xa
#define MAX_BUCK_BOOST_SINK				0x5

static const struct regmap_range max_tcpci_tcpci_range[] = {
	regmap_reg_range(0x00, 0x95)
};
@@ -202,30 +197,47 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
	tcpm_pd_receive(chip->port, &msg, rx_type);
}

static int get_vbus_regulator_handle(struct max_tcpci_chip *chip)
{
	if (IS_ERR_OR_NULL(chip->vbus_reg)) {
		chip->vbus_reg = devm_regulator_get_exclusive(chip->dev,
							      "vbus");
		if (IS_ERR_OR_NULL(chip->vbus_reg)) {
			dev_err(chip->dev,
				"Failed to get vbus regulator handle\n");
			return -ENODEV;
		}
	}

	return 0;
}

static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink)
{
	struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
	u8 buffer_source[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SOURCE};
	u8 buffer_sink[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SINK};
	u8 buffer_none[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_OFF};
	struct i2c_client *i2c = chip->client;
	int ret;

	struct i2c_msg msgs[] = {
		{
			.addr = MAX_BUCK_BOOST_SID,
			.flags = i2c->flags & I2C_M_TEN,
			.len = 2,
			.buf = source ? buffer_source : sink ? buffer_sink : buffer_none,
		},
	};

	if (source && sink) {
		dev_err(chip->dev, "Both source and sink set\n");
		return -EINVAL;
	}

	ret = i2c_transfer(i2c->adapter, msgs, 1);
	ret = get_vbus_regulator_handle(chip);
	if (ret) {
		/*
		 * Regulator is not necessary for sink only applications. Return
		 * success in cases where sink mode is being modified.
		 */
		return source ? ret : 1;
	}

	if (source) {
		if (!regulator_is_enabled(chip->vbus_reg))
			ret = regulator_enable(chip->vbus_reg);
	} else {
		if (regulator_is_enabled(chip->vbus_reg))
			ret = regulator_disable(chip->vbus_reg);
	}

	return ret < 0 ? ret : 1;
}