Commit 28bf22ef authored by Mårten Lindahl's avatar Mårten Lindahl Committed by Guenter Roeck
Browse files

hwmon: (pmbus) Add get_voltage/set_voltage ops



The pmbus core does not have operations for getting or setting voltage.
Add functions get/set voltage for the dynamic regulator framework.

Signed-off-by: default avatarMårten Lindahl <marten.lindahl@axis.com>
Link: https://lore.kernel.org/r/20220503104631.3515715-5-marten.lindahl@axis.com


[groeck: cosmetic alignment / empty line fixes]
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent 3aa74796
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -2634,11 +2634,78 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
	return 0;
}

static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
{
	struct device *dev = rdev_get_dev(rdev);
	struct i2c_client *client = to_i2c_client(dev->parent);
	struct pmbus_data *data = i2c_get_clientdata(client);
	struct pmbus_sensor s = {
		.page = rdev_get_id(rdev),
		.class = PSC_VOLTAGE_OUT,
		.convert = true,
	};

	s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
	if (s.data < 0)
		return s.data;

	return (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
}

static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
				       int max_uv, unsigned int *selector)
{
	struct device *dev = rdev_get_dev(rdev);
	struct i2c_client *client = to_i2c_client(dev->parent);
	struct pmbus_data *data = i2c_get_clientdata(client);
	struct pmbus_sensor s = {
		.page = rdev_get_id(rdev),
		.class = PSC_VOLTAGE_OUT,
		.convert = true,
		.data = -1,
	};
	int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
	int low, high;

	*selector = 0;

	if (pmbus_check_word_register(client, s.page, PMBUS_MFR_VOUT_MIN))
		s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_MFR_VOUT_MIN);
	if (s.data < 0) {
		s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_VOUT_MARGIN_LOW);
		if (s.data < 0)
			return s.data;
	}
	low = pmbus_reg2data(data, &s);

	s.data = -1;
	if (pmbus_check_word_register(client, s.page, PMBUS_MFR_VOUT_MAX))
		s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_MFR_VOUT_MAX);
	if (s.data < 0) {
		s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_VOUT_MARGIN_HIGH);
		if (s.data < 0)
			return s.data;
	}
	high = pmbus_reg2data(data, &s);

	/* Make sure we are within margins */
	if (low > val)
		val = low;
	if (high < val)
		val = high;

	val = pmbus_data2reg(data, &s, val);

	return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
}

const struct regulator_ops pmbus_regulator_ops = {
	.enable = pmbus_regulator_enable,
	.disable = pmbus_regulator_disable,
	.is_enabled = pmbus_regulator_is_enabled,
	.get_error_flags = pmbus_regulator_get_error_flags,
	.get_voltage = pmbus_regulator_get_voltage,
	.set_voltage = pmbus_regulator_set_voltage,
};
EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, PMBUS);