mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	hwmon: (pmbus) Introduce and use cached vout margins
When setting a new voltage the voltage boundaries are read every time to check that the new voltage is within the proper range. Checking these voltage boundaries consists of reading one of PMBUS_MFR_VOUT_MIN/ PMBUS_VOUT_MARGIN_LOW registers and then PMBUS_MFR_VOUT_MAX/ PMBUS_VOUT_MARGIN_HIGH together with writing the PMBUS_CLEAR_FAULTS register. Since these boundaries are never being changed, it can be cached and thus saving unnecessary smbus transmissions. Signed-off-by: Mårten Lindahl <marten.lindahl@axis.com> Link: https://lore.kernel.org/r/20220614093856.3470672-2-marten.lindahl@axis.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
		
							parent
							
								
									b674bcb13f
								
							
						
					
					
						commit
						07fb76273d
					
				
					 1 changed files with 61 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -104,6 +104,9 @@ struct pmbus_data {
 | 
			
		|||
 | 
			
		||||
	s16 currpage;	/* current page, -1 for unknown/unset */
 | 
			
		||||
	s16 currphase;	/* current phase, 0xff for all, -1 for unknown/unset */
 | 
			
		||||
 | 
			
		||||
	int vout_low[PMBUS_PAGES];	/* voltage low margin */
 | 
			
		||||
	int vout_high[PMBUS_PAGES];	/* voltage high margin */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct pmbus_debugfs_entry {
 | 
			
		||||
| 
						 | 
				
			
			@ -2848,6 +2851,58 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
 | 
			
		||||
{
 | 
			
		||||
	struct pmbus_data *data = i2c_get_clientdata(client);
 | 
			
		||||
	struct pmbus_sensor s = {
 | 
			
		||||
		.page = page,
 | 
			
		||||
		.class = PSC_VOLTAGE_OUT,
 | 
			
		||||
		.convert = true,
 | 
			
		||||
		.data = -1,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (!data->vout_low[page]) {
 | 
			
		||||
		if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
 | 
			
		||||
			s.data = _pmbus_read_word_data(client, page, 0xff,
 | 
			
		||||
						       PMBUS_MFR_VOUT_MIN);
 | 
			
		||||
		if (s.data < 0) {
 | 
			
		||||
			s.data = _pmbus_read_word_data(client, page, 0xff,
 | 
			
		||||
						       PMBUS_VOUT_MARGIN_LOW);
 | 
			
		||||
			if (s.data < 0)
 | 
			
		||||
				return s.data;
 | 
			
		||||
		}
 | 
			
		||||
		data->vout_low[page] = pmbus_reg2data(data, &s);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data->vout_low[page];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pmbus_regulator_get_high_margin(struct i2c_client *client, int page)
 | 
			
		||||
{
 | 
			
		||||
	struct pmbus_data *data = i2c_get_clientdata(client);
 | 
			
		||||
	struct pmbus_sensor s = {
 | 
			
		||||
		.page = page,
 | 
			
		||||
		.class = PSC_VOLTAGE_OUT,
 | 
			
		||||
		.convert = true,
 | 
			
		||||
		.data = -1,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (!data->vout_high[page]) {
 | 
			
		||||
		if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MAX))
 | 
			
		||||
			s.data = _pmbus_read_word_data(client, page, 0xff,
 | 
			
		||||
						       PMBUS_MFR_VOUT_MAX);
 | 
			
		||||
		if (s.data < 0) {
 | 
			
		||||
			s.data = _pmbus_read_word_data(client, page, 0xff,
 | 
			
		||||
						       PMBUS_VOUT_MARGIN_HIGH);
 | 
			
		||||
			if (s.data < 0)
 | 
			
		||||
				return s.data;
 | 
			
		||||
		}
 | 
			
		||||
		data->vout_high[page] = pmbus_reg2data(data, &s);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data->vout_high[page];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = rdev_get_dev(rdev);
 | 
			
		||||
| 
						 | 
				
			
			@ -2883,24 +2938,13 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
 | 
			
		|||
 | 
			
		||||
	*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);
 | 
			
		||||
	low = pmbus_regulator_get_low_margin(client, s.page);
 | 
			
		||||
	if (low < 0)
 | 
			
		||||
		return low;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	high = pmbus_regulator_get_high_margin(client, s.page);
 | 
			
		||||
	if (high < 0)
 | 
			
		||||
		return high;
 | 
			
		||||
 | 
			
		||||
	/* Make sure we are within margins */
 | 
			
		||||
	if (low > val)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue